-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #134 from activebridge/feature/add_posts
Feature/add posts
- Loading branch information
Showing
189 changed files
with
8,585 additions
and
329 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
172 changes: 172 additions & 0 deletions
172
_posts/2016-01-27-fighting-duplication-in-angularjs-controllers.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
--- | ||
author: Eugene Korpan | ||
author-position: | ||
background: fighting-duplication-in-angularjs-controllers-back | ||
category: engineering | ||
date: "2016-01-27" | ||
layout: post | ||
post-id: fighting-duplication-in-angularjs-controllers | ||
post-title: "Fighting duplication in AngularJS controllers" | ||
time-to-read: 4 min | ||
scripts: [post] | ||
hidden: true | ||
|
||
author-url: "" | ||
article-body: "" | ||
date-modified: "2020-02-25" | ||
description: "In this article I would like to discuss code duplication in AngularJS controllers" | ||
title: "How to fight with code duplication in Angular controllers" | ||
--- | ||
|
||
There are not so many challenges you face when working with AngularJS framework. In this article I would like to discuss code duplication in AngularJS controllers. Duplication is not something new but with AngularJS I saw some approaches that I didn’t like but those are widely used. | ||
|
||
So let’s say we have a simple forum app. The home page displays the list of all posts and user is able to like or dislike particular post. In AngularJS controller we would have someting like: below I’m going to use coffeescript. | ||
|
||
```coffeescript | ||
|
||
forumApp.controller 'PostsController', [ | ||
'$scope', 'Post' | ||
($scope, Post) -> | ||
|
||
$scope.posts = Post.query() | ||
|
||
markAsVoted = (post, vote) -> | ||
Post.update | ||
id: post.id | ||
vote: vote | ||
, (response) -> | ||
post.votes = response.votes | ||
|
||
$scope.voteUp = (post) -> | ||
markAsVoted(post, true) | ||
|
||
$scope.voteDown = (post) -> | ||
markAsVoted(post, false) | ||
|
||
] | ||
``` | ||
So far nothing special. We have two functions that get executed once user liked or disliked a post. | ||
|
||
Let’s move further. | ||
|
||
Then we need to implement a post page. When user found some post interesting he clicks on it and he is able to read the rest of the post and see other users’ comments. So we provide new AngularJS controller with appropriate template. | ||
|
||
```coffeescript | ||
|
||
forumApp.controller 'PostDetailsController', [ | ||
'$scope', 'Post', '$routeParams' | ||
($scope, Post, $routeParams) -> | ||
|
||
$scope.post = Post.get id: $routeParams.id | ||
] | ||
``` | ||
Then we think that user should be able to like/dislike this post within this page as well. On the template layer we would probably use ng-include and that’s it. What about AngularJS controller? First and easiest solution is simply copy and paste appropriate functions from PostsController. | ||
|
||
```coffeescript | ||
|
||
forumApp.controller 'PostDetailsController', [ | ||
'$scope', 'Post', '$routeParams' | ||
($scope, Post, $routeParams) -> | ||
|
||
$scope.post = Post.get id: $routeParams.id | ||
|
||
markAsVoted = (post, vote) -> | ||
Post.update | ||
id: post.id | ||
vote: vote | ||
, (response) -> | ||
post.votes = response.votes | ||
|
||
$scope.voteUp = (post) -> | ||
markAsVoted(post, true) | ||
|
||
$scope.voteDown = (post) -> | ||
markAsVoted(post, false) | ||
|
||
] | ||
``` | ||
And as we can see we’ve got the duplication. | ||
|
||
For some reason I found that many AngularJS users use $rootScope to solve this problem. If we go this way then our controllers would look like: | ||
|
||
```coffeescript | ||
|
||
forumApp.controller 'PostsController', [ | ||
'$scope', 'Post', '$rootScope' | ||
($scope, Post, $rootScope) -> | ||
|
||
$rootScope.postController = $scope | ||
|
||
$scope.posts = Post.query() | ||
|
||
markAsVoted = (post, vote) -> | ||
Post.update | ||
id: post.id | ||
vote: vote | ||
, (response) -> | ||
post.votes = response.votes | ||
|
||
$scope.voteUp = (post) -> | ||
markAsVoted(post, true) | ||
|
||
$scope.voteDown = (post) -> | ||
markAsVoted(post, false) | ||
|
||
] | ||
forumApp.controller 'PostDetailsController', [ | ||
'$scope', 'Post', '$routeParams', '$rootScope' | ||
($scope, Post, $routeParams, $rootScope) -> | ||
|
||
$scope.post = Post.get id: $routeParams.id | ||
|
||
$scope.voteUp = (post) -> | ||
$rootScope.postController.voteUp(post) | ||
|
||
$scope.voteDown = (post) -> | ||
$rootScope.postController.voteDown(post) | ||
] | ||
``` | ||
At first glance seems like delegating our functions to postsController solves the problem: no duplication, minimum updates in existing controllers. But I think this is totally wrong! In my ideal world developers just don’t use $rootScope. If we continue using this approach then the whole AngularJS app would turn to spaghetti, all controllers call functions in each other ruining single responsibility principle and hence would be hard to understand what is going on here, debug and maintain. | ||
|
||
I’m pretty sure there are many other better solutions to this problem and I would like to describe one of them. The idea is taken from ruby mixins and applying Decorator pattern. So we just extract duplicated code into a decorator and apply it for $scope of each controller we need. | ||
|
||
Here is how a decorator would look like: | ||
|
||
```coffeescript | ||
|
||
forumApp.factory 'postDecorator', [ | ||
'Post' | ||
(Post) -> | ||
markAsVoted = (post, vote) -> | ||
Post.update | ||
id: post.id | ||
vote: vote | ||
, (response) -> | ||
post.votes = response.votes | ||
|
||
$scope.voteUp = (post) -> | ||
markAsVoted(post, true) | ||
|
||
$scope.voteDown = (post) -> | ||
markAsVoted(post, false) | ||
] | ||
And then our controllers: | ||
|
||
forumApp.controller 'PostsController', [ | ||
'$scope', 'Post', 'postDecorator' | ||
($scope, Post, postDecorator) -> | ||
|
||
postDecorator($scope) | ||
|
||
$scope.posts = Post.query() | ||
] | ||
forumApp.controller 'PostDetailsController', [ | ||
'$scope', 'Post', '$routeParams', 'postDecorator' | ||
($scope, Post, $routeParams, postDecorator) -> | ||
|
||
postDecorator($scope) | ||
|
||
$scope.post = Post.get id: $routeParams.id | ||
] | ||
``` | ||
Looks much better, doesn’t it? |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
--- | ||
author: Alex Galushka | ||
author-position: "CEO / Tech lead and backend developer" | ||
background: five-ways-to-keep-your-code-cleen-back | ||
category: engineering | ||
date: "2016-02-02" | ||
layout: post | ||
post-id: five-ways-to-keep-your-code-cleen | ||
post-title: "5 ways to keep your code clean" | ||
time-to-read: 2 min | ||
scripts: [post] | ||
hidden: true | ||
|
||
author-url: "" | ||
article-body: "" | ||
date-modified: "2020-02-25" | ||
description: "Rails community's invented many gems what are constantly analyzing your code and they give you to know about | ||
stuff what you should improve" | ||
title: "How to Keep Your Code Clean" | ||
--- | ||
|
||
Do you think your code clean, useful and readable? I’m sure you're wrong! | ||
Rails community's invented many gems what are constantly analyzing your code and they give you to know about stuff what you should improve. | ||
Let me introduce some of these gems: | ||
|
||
`rails_best_practices` | ||
|
||
> ’sudo gem install rails_best_practices’ | ||
and run rails_best_practices .By the way, there are many configurations, so you should read documentation. Best Practices experience can be found on site | ||
|
||
|
||
`rubocop` | ||
|
||
> sudo gem install rubocop | ||
So you can run rubocop | ||
I have found a lot of tweaks in documentation | ||
|
||
`Flay` from Ruby Sadist | ||
|
||
> just install sudo gem install flay | ||
and run in command line flay app/models/*.rb | ||
|
||
Have you heard about Bullet gem? | ||
Improve your SQL queries with Bullet | ||
The Bullet gem is designed to help you increase your application’s performance by reducing the number of queries it makes. It will watch your queries while you develop your application and notify you when you should add eager loading (N+1 queries). When you’re using eager loading that isn’t necessary and when you should use a counter cache. | ||
add it into a Gemfile | ||
|
||
> gem 'bullet', group: 'development' | ||
Append to config/environments/development.rb initializer with the following code: | ||
|
||
> config.after_initialize do Bullet.enable = true Bullet.alert = true Bullet.bullet_logger = true Bullet.console = true Bullet.growl = trueend | ||
More information you can find on official GitHub page. | ||
What benefits are from Brakeman gem? Just install gem brakeman and run from app directory brakeman. So, after analyzing it provide information in next categories: | ||
|
||
SUMMARY | ||
SECURITY WARNINGS | ||
Controller Warnings | ||
Model Warnings | ||
|
||
P.S. | ||
You have to know Ruby Style Guide, Rails Style Guide and Better Specs or Rspec Best Practices. And gems described above should just help you fix missed! | ||
Have clean code! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
--- | ||
author: Alex Galushka | ||
author-position: "CEO / Tech lead and backend developer" | ||
background: simple-way-to-create-public-pages-back | ||
category: engineering | ||
date: "2016-02-02" | ||
layout: post | ||
post-id: simple-way-to-create-public-pages | ||
post-title: "Simple way to create public pages" | ||
time-to-read: 2 min | ||
scripts: [post] | ||
hidden: true | ||
|
||
author-url: "" | ||
article-body: "" | ||
date-modified: "2020-02-25" | ||
description: "So, it's generally understood, they are used when there is no need for dynamic info or pulling from the | ||
database" | ||
title: "How to Create Public Pages. Ruby" | ||
--- | ||
|
||
Have you ever heard about public pages in Ruby? And what does it mean? So, it's generally understood, they are used when there is no need for dynamic info or pulling from the database. | ||
As usual Ruby on Rails developers implement some pre-built gems. But I would like to show you another way to create public pages in your rails apps such as About and FAQ. By this means, if your public page doesn't have anything similar in your app layout you can put simple HTML page to your public folder. There is such way: | ||
|
||
```ruby | ||
class PagesController < ApplicationController | ||
def about | ||
end | ||
|
||
def faq | ||
end | ||
end | ||
``` | ||
However, I guess this kind of implementation is very complicated because we need to add many actions and routes to achieve the result. Nevertheless, one should not forget that the main REST principle says that everything is a resource. So let's look at this pages as resources. | ||
`routes.rb: | ||
get ':page', to: 'pages#show', as: :page | ||
pages_controller.rb:` | ||
|
||
```ruby | ||
class PagesController < ApplicationController | ||
def show | ||
render params[:page] | ||
end | ||
end | ||
``` | ||
Then, you should use path helper to get these pages: | ||
`page_path(:about), page_path(:faq)` | ||
But there is the possibility that user can pass the invalid value as page parameter and template missing exception resides with status 500 that is not good. To avoid that we will add constraints to our route. | ||
`routes.rb: | ||
get ':page', to: 'pages#show', as: :page, constraints: { page: /(howitworks|careers|about|faq)/ }` | ||
If you want to add a new public page you just need to create a view for it in ‘views/pages’ folder and add the constraint to routes. | ||
I think, this method will be ease to implement and achieve good results for building an app with public pages. |
64 changes: 64 additions & 0 deletions
64
...s/2016-02-02-unobtrusive-scripting-adapter-vs-remote-part-ajax-file-uploader.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
--- | ||
author: Alex Galushka | ||
author-position: "CEO / Tech lead and backend developer" | ||
background: simple-way-to-create-public-pages-back | ||
category: engineering | ||
date: "2016-02-02" | ||
layout: post | ||
post-id: unobtrusive-scripting-adapter-vs-remote-part-ajax-file-uploader | ||
post-title: "Unobtrusive scripting adapter vs Remotipart" | ||
time-to-read: 2 min | ||
scripts: [post] | ||
hidden: true | ||
|
||
author-url: "" | ||
article-body: "" | ||
date-modified: "2020-02-25" | ||
description: "Many of web applications require an easy and common way to upload different type data" | ||
title: "A definitive guide to Rails’ unobtrusive JavaScript adapter" | ||
--- | ||
|
||
In this short instruction, I would like to share how to use AJAX file upload in Ruby on Rails. Many of web applications require an easy and common way to upload different type data. To solve this issue, Rails has nice Unobtrusive scripting adapter. It takes care of remote forms and links to your application. But in fact, I actually think, there is one point it can not handle: the AJAX file upload. It is the provide the routes.rb: | ||
|
||
> get ':page', to: 'pages#show', as: :page | ||
pages_controller.rb: | ||
|
||
```ruby | ||
class PagesController<Application Controller | ||
def show | ||
render params[:page] | ||
end | ||
end | ||
``` | ||
|
||
ability to handle that to other libs by adding the custom event called`ajax: aborted: file`. | ||
|
||
|
||
I've made some experiments with deep insight of this method. I’ve found there is only one lib uses this event and provides the ability to upload files with remote forms. It's named the remote part. The remote part uses the iframe workaround. But there should be the other way to do it. | ||
Firstly, I am thinking about the formData interface but it is not supported in by Internet Explorer. So there is only one alternative left - base64. | ||
|
||
Let’s code some coffee: | ||
|
||
```javascript | ||
$(document).on 'ajax:aborted:file', 'form', (e, inputs) -> | ||
j = 1 | ||
form = $(@ | ||
$.map inputs, (input, i) -> | ||
fr = new FileReader() | ||
fr.readAsDataURL(input.files[0]) | ||
fr.onload = -> | ||
form.append("<input type='hidden' name='#{input.name}' value='#{fr.result}' />") | ||
$.rails.handleRemote(form) if (inputs.length == j) | ||
j++ | ||
return false | ||
``` | ||
In such a way the files will be sending as base64 strings under same names. Next step is decoding the files on the server. We were using the carrier wave for file uploading and I've found the carrierwave-base64 gem that is doing exactly what I need. | ||
Just add it to your Gemfile, and mount the uploader mount_base64_uploader :image, ImageUploader. | ||
Also, it is one more additional step is to add the parameter filter to keep your logs clean. | ||
> config.filter_parameters += [:image] | ||
All browser is supported except IE9 and lower. In case IE9, the form will be submitted to regular HTML type. | ||
I have extracted the javascript to separate rails gem. Also, it would be nice to have the rack middleware to encode the base64 string on middleware level. |
Oops, something went wrong.