Single Responsibility Principle in Ruby

Single Responsibility Principle in Ruby

Assume that we already had the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class AuthenticatesUser
  def authenticate(email, password)
    if matches?(email, password)
     do_some_authentication
    else
      raise NotAllowedError
    end
  end

  private
  def matches?(email, password)
    user = find_from_db(:user, email)
    user.encrypted_password == encrypt(password)
  end
end

The AuthenticatesUser class is responsible for authenticating the user as well as knowing if the email and password match the ones in the database. It has two responsibilities, and according to the principle it should only have one, let’s extract one.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class AuthenticatesUser
  def authenticate(email, password)
    if MatchesPasswords.new(email, password).matches?
     do_some_authentication
    else
      raise NotAllowedError
    end
  end
end

class MatchesPasswords
  def initialize(email, password)
     @email = email
     @password = password
  end

  def matches?
    user = find_from_db(:user, @email)
    user.encrypted_password == encrypt(@password)
  end
end

I’ve used a refactoring technique called “Extract Class” and then use it on the class I already had, this is called sharing behaviour through “Composition”.

So far so good, That’s it!!! See ya!!! :)

Push to Multiple Git Repositories

Push to Multiple Git Repositories

Here’s a cool little trick I’ve found out about the other day. Even though Git is a distributed revision control system, there are times when you need to push to two systems at once. In my case those systems are Github and Heroku. Here is a simple way to do it by modifying your .git/config file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[core]
  repositoryformatversion = 0
  filemode = true
  bare = false
  logallrefupdates = true
[remote "heroku"]
  url = git@heroku.com:pgsearch.git
  fetch = +refs/heads/*:refs/remotes/heroku/*
[remote "github"]
  url = git@github.com:Bunlong/rvm.git
  fetch = +refs/heads/*:refs/remotes/github/*
[remote "origin"]
  url = git@heroku.com:pgsearch.git
  url = git@github.com:Bunlong/rvm.git

The “heroku” and “github” remotes are generated by git and are created in the setup instructional steps of each service respectively. I went ahead and manually added the remote “origin” and just copied the url variable from the other remotes. You’ll now be able to push to both by calling “git push origin” and then you can fetch from each one as individually needed.

So far so good, That’s it!!! See ya!!! :)

Why Choose Ruby on Rails Framework?

Why Choose Ruby on Rails Framework?

Ruby on rails is one of the popular development frameworks for regular websites as well as kind of tools, web and mobile apps or combinations of all. Some of the following reasons which makes it popular among others:

Higher Flexibility - In Ruby on Rails, it is easy to mold the platform to suit different business needs more efficiently than other frameworks. We can quickly mock up a working prototype, and then see how things work and then build on the idea. Faster Development Speed - In Rails, there are lots of in-built components(called gems) available which we can re-use to build the application rather than building everything from scratch.

Agile Development at its best - Ruby on Rails is developed using the MVC design pattern along with the agile methodology which is well suited for web application development with fast changing requirements.

Integrated testing tools - Rails features a convenient testing tool as it automatically starts producing the skeleton test code in background at the time of development. Rails tests can also simulate browser requests and thus you can test your application’s response without having to test it over browser.

Compatibility - Rails development is compatible with a wide range of web servers and databases; which ultimately makes the web deployment easier.Cost-effective Web solutions - As it is an open source framework this helps in developing cost-effective web applications without sacrificing performance, speed and quality.

Reasons to Bring Ruby on Rails Development on Board

Reasons to bring Ruby on Rails Development on Board

Ruby on Rails is an innovation in development framework. It encompasses all the necessary elements to boost a web application’s performance. This framework is designed to address agile development and deliver productivity as well as flexibility to Ruby on Rails developers. Developed using Ruby programming language, it has transformed the world of web development through its practical approach.

Ruby on Rails is built upon two programming philosophies

Convention over Configuration: Developers only need to write codes for the irregular or unconventional aspects of the web application.

Don’t Repeat Yourself: The data is stored in definite place. It saves time and reduces code.

Advantages of Ruby on Rails

Faster Development: Rails framework enables the developers to write concise and clear syntax and produces fewer codes than its competitors. Therefore it requires less time to code and generates fewer errors. On the other hand it facilitates the programmers to maintain much less code. It is also enabled to integrate numerous tools to automate repetitive tasks such as managing database errors, creating forms etc… it simplifies development process because the language is lightweight and easily readable, almost like the natural language.

Increases Productivity: Rails framework is specifically featured to reduce the development aspects of applications, instead leveraging creativity and uniqueness of the web application. It empowers productivity by eliminating repetitive programming codes.

Assists Development of Creative Interfaces: Rails includes numerous integrations to enable developers in creating rich, intriguing user interfaces. Integrated JavaScript framework is easier to activate and features elements like apparition progressive, drag & drop and many more to ease the designing aspects of the application.

Model View Controller Design Pattern: Rails is developed on MVC architecture that separates the development logics from the presentation layer. It provides a well-structured application to the developers and the code is maintained in a logical and coherent manner. It encourages abstraction in the application and enables the team to work on separate modules without depending on each other. It focuses on the features rather than minute details. Rails framework delivers ease of project development, conciseness and faster deployment of application.

Rails Development makes web app development easier because it involves less coding while implementing new changes and updates into the development process. It enables the organizations to meet all the business requirements within the budget and schedule. So far so good, That’s it!!! See ya!!! :)

Ruby DSL (Domain-Specific Language)

What is a DSL?

A domain-specific language (DSL) is a computer language specialized to a particular application domain. This is in contrast to a general-purpose language (GPL), which is broadly applicable across domains, and lacks specialized features for a particular domain.

A DSL is like a mini language inside of a language. It’s a specific syntax for describing a domain/area of your application. Think of a DSL like a mini game within a game… like when you were raising/racing Chocobos in Final Fantasy 7. A DSL in Ruby is still written in Ruby, it just provides a nicer interface and language for performing common tasks.

DSL you have seen

You may not have realized it, but if you write Rails applications you most likely work with a variety of DSLs every day. Below are a few examples of some commons ones.

Rails Routing

1
2
3
4
Rails.application.routes.draw do
  root 'pages#home'
  resources :pages, only: [:index, :show]
end

Rspec

1
2
3
4
5
6
7
8
9
describe Array do
  describe "includes_subset?" do
    it "finds subsets" do
      a = [1,2,3,4,5]
      b = [1,2]
      expect(a.includes_subset?(b)).to eq(true)
    end
  end
end

Capistrano

1
2
3
4
5
6
7
8
9
role :app, %w{deploy@localhost}

server 'localhost',
  user: 'deploy',
  roles: %w{app},
  ssh_options: {
    keys: %w(/home/deploy/.ssh/id_rsa),
    auth_methods: 'publickey'
  }

Blocks are Key to DSLs

Knowing how blocks work is crucial to understanding how DSLs work. I think of a block in Ruby as basically just a chunk of code that you can pass around to other methods. If you’re used to writing Javascript you’re definitely comfortable passing around functions, and blocks in Ruby are fairly similar to that.

1
2
3
4
5
double = ->(num) {
  num * 2
}
puts double.call(2)
# 4

Passing Blocks
You’ve most likely used blocks before when calling the each method on an Array, or the collect method.

1
2
3
4
[1, 2, 3].each do |item|
  puts item * 2
end
# 2, 4, 6

What you are doing is passing the block of code between do and end to the each method of the Array class.

Receiving Blocks
On the recipients side, there are a couple ways to receive the block that was passed. The first way is via the yield keyword in Ruby. yield will call the block of code that was passed to the method. You can even pass variables to the block of code.

1
2
3
4
5
6
7
8
class Array
  def each
    array_size = self.size - 1
    for i in 0..array_size
      yield self[i]
    end
  end
end

There is an alternate way of receiving a block of code that is called a named-block. This essentially allows you to save the block of code to a variable, which gives you the flexibility to pass the block on to another method. If you wish to execute the code inside of the block, you can do so via the call method on it.

1
2
3
4
5
6
7
8
class Array
  def each(&block)
    array_size = self.size - 1
    for i in 0..array_size
      block.call self[i]
    end
  end
end

Block Context
Normally a block has the context of the place it was instantiated. It is possible to change this, to be the place where it is being called, but to do this instead of doing the usual yield or block.call(), you call it via the instance_eval(&block) method.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Dummy
  def initialize
    @name = "Inside"
  end

  def print_name(&block)
    # Has outside context
    block.call
    # Has inside context
    instance_eval(&block)
  end
end

@name = "Outside"

Dummy.new.print_name do
  puts @name
end

Create your own DSL
Create a Ruby DSL to generate HTML. The output was to look like the following, and below is how the DSL should be called. To each HTML element you can pass text, options (html attributes), and a block. All are optional.

1
2
3
4
5
6
7
8
9
10
<html>
  <body>
    <div id="container">
      <ul class="pretty">
        <li class="active">Item 1</li>
        <li>Item 2</li>
      </ul>
    </div>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
output = FancyMarkup.new.document do
  body do
    div id: "container" do
      ul class: "pretty" do
        li "Item 1", class: :active
        li "Item 2"
      end
    end
  end
end

The solution I eventually came up with (after some serious refactoring) is below. I used some Ruby meta-programming by not actually defining methods for each HTML element, but rather utilizing method_missing as a catch-all, which then passes the element name, the args, and the block on to the tag method, which does the heavy lifting of generating the HTML.

One other thing I utilized here was that you can also check if a block was actually passed to the method by using the block_given? method.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
class FancyMarkup

  attr_accessor :indents, :html

  def initialize
    @indents = 0
    @html = ""
  end

  # Catch-all method to avoid creating methods
  # for each HTML element.
  def method_missing(m, *args, &block)
    tag(m, args, &block)
  end

  # The first method called when creating an
  # HTML document.
  def document(*args, &block)
    tag(:html, args, &block)
  end

  private

  # Create the HTML tag
  # @param (String|Symbol) HTML tag (ul, li, strong, etc...)
  # @param (Array) Can contain a String of text or a Hash of attributes
  # @param (Block) An optional block which will further nest HTML
  def tag(html_tag, args, &block)
    content = find_content(args)
    options = html_options(find_options(args))

    html << "\n#{indent}<#{html_tag}#{options}>#{content}"
    if block_given?
      @indents += 1
      instance_eval(&block)
      @indents -= 1
      html << "\n#{indent}"
    end
    html << "</#{html_tag}>"
  end

  # Searching the tag arguments, find the text/context element.
  def find_content(args)
    args.select{|arg| arg.is_a? String}.first || nil
  end

  # Searching the tag arguments, find the hash/attributes element
  def find_options(args)
    args.select{|arg| arg.is_a? Hash}.first || {}
  end

  # Indent output number of spaces
  def indent
    "  " * indents
  end

  # Build html options string from Hash
  def html_options(options)
    options.collect{|key, value|
      value = value.to_s.gsub('"', '\"')
      " #{key}=\"#{value}\""
    }.join("")
  end
end

So far so good, I’ve realized how important blocks are to Ruby. Learning them well and understanding how DSLs work will improve the Ruby code that I write. That’s it!!! See ya!!!

The Developer View

The Developer View

A developer might be someone who writes code, or it may be an interaction designer, a graphic designer, or a tester. In this document describes the things that happend in between the daily standup meetings.

1. Tools and Practices
Tools don’t solve your problem; people do. Tools just help. It’s crucial to choose the right practices to go with your tools – the right ways to use your tools so that they do the most for you.

And day-to-day as required, we discuss how our tools are helping or hurting us, and how they can work better for us. When things aren’t working quite right, we’ll first try to look at the way we’re using the tool; changing our practices is less costly and disruptive than changing a tool. But we occasionally change the tool as well.

2. Pair Programming
Pair programming involves two programmers at a single computer (each with a monitor and keyboard of their own) working together on a single task. As a unit, they maintain a hight level of quality as well as ensuring a broad perspective on problem solving. For many complex problems and architectural design exercises, pair programming can drastically reduce defects and helps ensure that code requires a minimum amount of rewriting.

When used effectively, pair programming reduces the overall cost of development and maintenance.

We look at each coding and design task determine if pairing is appropriate, and at the discretion of the project team, many coding tasks are performed solo. When this happens, the code must pass code review before moving to QA.

3. Test-Driven Development

4. Behavior-Driven Development

5. Code Review
Although many tasks call for pair programming, it is simply not practical or efficient to pair on every task. Then tasks are tackled by a solo developer, their work must always be reviewed by another developer on the team.

Our task manangement system is configured to give a task two paths out of development. One path is “Completed by Pair, Ready for QA” Tasks handled by a solo developer follow an alternate path: “Completed Solo, Ready for Code Review”. That allows us to ensure that every piece of code that gets delivered to our customers thas been seen by at least two developers. Of course, that doesn’t mean there aren’t any problems, but it does shorten an important feedback loop, catching most problems early, when fixing them is cheapest.

6. Continuous Integration
Continuous Integration (CI) ensures that an application is healthy by making sure that automated test pass on a neutral machine (not just a specific developer’s machine). Whenever anybody commits code to the central code repository, a CI server downloads the code and runs the build to ensure that the tests are still passing. If any of the automated tests fail, the build fails and the entire team is notified.

We believe that the build should always be passing, and if somebody breaks the build, it needs to be fixed immediately before futher development can task place.

7. Code Coverage
Code coverage has many definitions, but it normally represents the percentage of lines (or branches) in a software project that are covered by automated tests. A low score probably means bad code, but a hight score doesn’t necessarily mean good code.

At the start of a project, the project team can choose what code coverage standard to enforce.

8. Distributed Source Control
We uses a distributed source control system called Git (and Github) to store and track source code and other development-related artifacts.

This is more important than it may first appear. Traditional, centralized source control systems inhibit agile teams by making branch and merge operations expensive. This make parallel, distributed development more costly. So much so, in fact, that source control can become a bottleneck on overall productivity of the team.

9. Fridays (20% Time)
On Fridays, we don’t do billable client work. We spend our time on things that improve our lives as developer, our own pet project or passions, and for giving back to the rich sea of open-source software (espcially development tools) in which our business swims and thrives.

Versioning With PaperTrail on Rails

Versioning with PaperTrail on Rails

Imagine the situation, You open your website’s admin page to do some clean up, find some old data that hasn’t been viewed by anyone for ages, and delete it. Deletion succeeds and everything is okay, but after a second “No!!! That data contained VERY IMPORTANT INFORMATION that could possibly change the world!”, you realize. But, it’s gone and the world remains unchanged (well, there is still a chance for recovery if you have a backup of the Database).

Can we prevent this situation in our Rails application? Yes, for sure we can. Well, in this article, we are going to talk about how to implement a “History” page and an “undo” button (as well as “redo”) with the help of the paper_trail gem.

We are going to build a simple blog that allows to add, update, and destroy posts. And would be able to undo every action related to the posts (for example, undoing an unintentional delete). We will also provide a “History” page displaying a list of actions (and some other info) that users performed while working with posts.

Create Rails Project
Run command below to create a new Rails application:

1
rails new blog -d mysql

Add Gems
We will add a gems to our Gemfile. paper_trail, it will help us to create both the “History” page and an “undo” button:

Gemfile
1
gem 'paper_trail', '~> 3.0.1'

The blog app has one controller (apart from the ApplicationController), PostsController, that will be used to manage our posts. Initially, it has seven default methods: index, new, create, destroy, edit and update, along with a number of views related to them. I will not go into the details on how to create these methods and views, because they are really basic (you can create them using rails g scaffold Posts).

The blog contains a model: Post. The posts table have the following columns: id, title, body, created_at, updated_at.

And routes file will looks like:

routes.rb
1
2
root to: 'posts#index'
resources :posts

At this point, we are ready to setup paper_trail. First of all, create a special table to store the versions (it’s a cool feature of paper_trail – if we want to clear old versions later, we would need only to access one table).

Run command below to generate and migrate paper_trail:

1
2
bundle exec rails generate paper_trail:install
bundle exec rake db:migrate

Create and apply the required migration. Add the following line to your Post model (app/models/post.rb):

post.rb
1
2
3
class Post < ActiveRecord::Base
  has_paper_trail
end

Well! Now, all changes to the posts table will be audited automatically. How cool is that?

You can also specify which changes should not be tracked. For example, if posts had a view_count column in and we did not want to track changes to it, the modification looks like in (app/models/post.rb):

post.rb
1
has_paper_trail ignore: [:view_count]

Some fields can be skipped, they will neither be tracked nor included in the serialized version of the object (app/models/post.rb):

post.rb
1
has_paper_trail skip: [:view_count]

Or can specified as well (app/models/post.rb):

post.rb
1
has_paper_trail on: [:update, :create]

Or provide conditions on whether to track the event:

post.rb
1
2
has_paper_trail if: Proc.new { |t| t.title.length > 10 },
                unless: Proc.new { |t| t.body.blank? }

Display the Log
Now, you probably want to display the audited versions, It’s easy, just, add the following route:

routes.rb
1
2
3
root to: 'posts#index'
resources :posts
get '/posts/history', to: 'posts#history', as: :posts_history

To the history page for Posts. If your app has many models that are being audited, it’s a good idea to create a separate VersionsController and place all versions-related methods there. However, in our case, only the Post model is being audited, so let’s stick with one controller.

Add a history method to the controller (app/controllers/posts_controller.rb):

posts_controller.rb
1
2
3
def history
  @versions = PaperTrail::Version.order('created_at DESC')
end

Note that we have to use PaperTrail::Version, not just Version. This line of code extracts all the recorded events from the versions table that we have created earlier and sorts them by the creation date. In a real app, paginating these events by using will_paginate or kaminari gem is advisable.

Rendering the view history (app/views/posts/history.html.erb):

history.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<div class="container">
  <h1>History</h1>
 
  <ul>
    <% @versions.each do |version| %>
      <li>
        <%= l(version.created_at, format: "%-d.%m.%Y %H:%M:%S %Z") %><br/>
        Event ID: <%= version.id %><br/>
        <b>Target:</b> <%= version.item_type %>
        <small>(id: <%= version.item_id %>)</small>; <b>action</b> <%= version.event %>;<br/>
        <div>
          More info:
          <pre><%= version.object %></pre>
        </div>
      </li>
    <% end %>
  </ul>
</div>

Here is the data being displayed:

Data Description
version.created_at When this event took place.
version.id ID of this event.
version.item_type Model name for the event. In our case, it’s Post.
version.item_id ID of the resource (Post) that was changed.
version.event The action applied to the resource (create, update, destroy).version.object, Full dump of the resource that was changed.


There are some things that could be improved. For example, which fields were changed (especially for the update action)? Well, that is very easy to implement.

Run command below to create and apply migration:

1
2
rails g migration add_object_changes_to_versions object_changes:text
rake db:migrate

This can also be done when setting up paper_trail. You just need to provide an appropriate option to the generator below:

1
rails generate paper_trail:install --with-changes

No further action is required, paper_trail will automatically diff the versions.

Now, we can add a new div with version.changeset block to our view (app/views/posts/history.html.erb):

history.html.erb
1
2
3
4
5
6
[...]
<div>
  Changeset:
  <pre><%= version.changeset %></pre>
</div>
[...]

It will display attribute values before and after the event (if an attribute remained unchanged it will not be displayed).

Track User-Specific Information
Okay, now we know when of our precious blog post deletion. But, we don’t know who, High time to fix this issue.

Let’s track an IP address of the user responsible for the action. Of course, an IP address can be forged, but the main point here is to explain how to store metadata alongside with the event’s data. Go on and create a new migration below:

1
2
rails g migration add_ip_to_versions ip:string
rake db:migrate

paper_trail will not store anything in the ip column, by default, so we need to help it out a bit. Add this method to the ApplicationController (app/controllers/application_controller.rb):

application_controller.rb
1
2
3
def info_for_paper_trail
  { ip: request.remote_ip }
end

paper_trail will use this method to fetch some additional info and store it as metadata. If you are using Rails 3 or protected_attributes with Rails 4, you will also need to create an initializer (initializers/paper_trail.rb):

paper_trail.rb
1
2
3
4
5
module PaperTrail
  class Version < ActiveRecord::Base
    attr_accessible :ip
  end
end

Metadata can also be provided in the model (app/models/post.rb) like this (presuming we have a timestamp column):

post.rb
1
has_paper_trail meta: { timestamp: Time.now }

The last thing to do is add a line into view (app/views/posts/history.html.erb):

history.html.erb
1
2
3
[...]
<b>Remote address:</b> <%= version.ip %><br/>
[...]

Undo an Action
Let’s move on, allowing the user to undo their actions. Create undo method in posts controller (app/controllers/posts_controller.rb) that will undo the requested action:

posts_controller.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def undo
  @post_version = PaperTrail::Version.find_by_id(params[:id])

  begin
    if @post_version.reify
      @post_version.reify.save
    else
      @post_version.item.destroy
    end
    flash[:success] = "Undid that..."
  rescue
    flash[:alert] = "Failed undoing the action..."
  ensure
    redirect_to root_path
  end
end

The above code, find a version by id and then check if there are previous versions available for the resource using the reify method, this method will return nil if the resource was just created in the current version (obviously, if the resource was just created it does not have any previous versions.) Either rollback to the previous version using @post_version.reify.save or destroy the newly created resource using @post_version.item.destroy (the @post_version.item returns the actual resource).

And routes file will looks like:

routes.rb
1
2
3
4
root to: 'posts#index'
resources :posts
get '/posts/history', to: 'posts#history', as: :posts_history
post '/posts/:id/undo', to: 'posts#undo', as: :undo

Then put this undo link into the flash message, so make sure to render it somewhere in your layout (app/views/layouts/application.html.erb):

application.html.erb
1
2
3
4
5
6
7
8
<div class="container">
  <% flash.each do |key, value| %>
    <div class="alert alert-<%= key %>">
      <button type="button" class="close" data-dismiss="alert">&times;</button>
      <%= value.html_safe %>
    </div>
  <% end %>
</div>

Then create a private method in the PostsController that generates an undo link:

posts_controller.rb
1
2
3
4
5
[...]
private
def make_undo_link
  view_context.link_to 'Undo that plz!', undo_path(@post.versions.last), method: :post
end

We cannot use link_to inside the controller, so the reference to view_context points to the actual view. @post.versions fetches all the versions for the Post resource and @post.versions.last gets the latest one. This method can be used like this in PostsController (app/controllers/posts_controller.rb):

posts_controller.rb
1
2
3
4
5
6
7
8
9
10
11
[...]
def update
  @post = Post.find_by_id(params[:id])
  if @post.update_attributes(post_params)
    flash[:success] = "Post was updated! #{make_undo_link}"
    redirect_to post_path(@post)
  else
    render 'edit'
  end
end
[...]

Make sure to add it to the create and destroy methods as well.

Okay, I have undone an action… but now I want to redo it. Here, we should introduce a redo link that reverts the undo. There are only few modifications needed.

Then create another private method in PostsController (app/controllers/posts_controller.rb):

posts_controller.rb
1
2
3
4
5
6
7
[...]
private
def make_redo_link
  params[:redo] == "true" ? link = "Undo that plz!" : link = "Redo that plz!"
  view_context.link_to link, undo_path(@post_version.next, redo: !params[:redo]), method: :post
end
[...]

This method is very similar to make_undo_link. The main difference is the params[:redo] which is true of false. Based on this parameter, change the text of the link – the URL actually remains unchanged. This is because redoing basically means reverting to the previous version, which is absolutely the same as the undo action.

Then alter the flash message inside the undo method in PostsController:

posts_controller.rb
1
2
3
4
5
[...]
def undo
[...]
  flash[:success] = "Undid that! #{make_redo_link}"
[...]

That’s it, users can undo and redo their actions as many times and they want, every time being recorded by paper_trail.

The only one problem is that the versions table can become fat very quickly. This should probably be handled with some background process to remove old entries. The job would use something like:

1
PaperTrail::Version.delete_all ["created_at < ?", 1.week.ago]

You also can limit the number of created versions per object by adding this line into an initializer:

1
PaperTrail.config.version_limit = 3

So far so good, That’s it!!! See ya!!! :)

Ruby on Rails Passing Optional Locals to Partials

Ruby on Rails Passing Optional Locals to Partials

When passing locals to Rails partials, you might run into cases where you need to pass optional locals in some places, but don’t want to pass it in every other place where you use the partial.

As an example, you have a _post partial which you render like this:

1
<%= render 'post', post: post %>

And now you want to render the same partial from another view, but this time you want to pass a boolean flag to tell the partial to render the author bio as well:

1
<%= render 'post', post: post, show_author_bio: true %>

If we used the show_author_bio local in the partial, it would break the other view which does not know this local. To use it safely, we can use the local_assigns hash:

1
2
3
4
5
6
7
<h1><%= post.title %></h1>

<% if local_assigns[:show_author_bio] %>
  <%= render 'author_bio', author: post.author %>
<% end %>

<%= post.body %>

We’re using it for passing a boolean value here, we could pass in any other object as well. For instance, we could pass in an optional author object:

1
2
3
<% if local_assigns.has_key?(:author) %>
  <%= render 'author_bio', author: author %>
<% end %>

DHH (David Heinemeier Hansson) opened an issue (#18962) about this as well, and had an interesting comment to make about this feature.

So far so good, That’s it!!! See ya!!! :)

How to Debug a Ruby on Rails Application

How to Debug a Ruby on Rails Application

This article I will show you how you can easily debug your Ruby on Rails application.

Setup
If you’re using the default Rails Rack server, Webrick – the best debugging tool I’ve been able to find out there is pry. First you need to add the pry gem to your Gemfile. Since this is used for development purposes. Open up your Gemfile file so that it looks sometings like:

Gemfile
1
2
3
group :development, :test do
  gem 'pry'
end

Then run bundle install to install it:

1
bundle install

Usage
Basically, Whenever one of your actions crashes and you can’t figure out straight away what caused it to crash. What you need to do is invoke binding.pry somewhere in your code, which will create a Pry session at the point it’s called. This will pretty much open a ‘developer console’ where you can play around with all the objects that have been defined up until you called binding.pry. Then you can then easily debug your action, like you’d regularly do in an irb console. When you’re done with the Pry session the program will resume.

Here’s how this would work in a regular create action from Users controller:

users_controller.rb
1
2
3
4
5
6
7
8
9
10
11
12
def create
  user = User.create(user_params)
  binding.pry # Start a pry session to see if the new user looks the way we want
  if user.save
     flash.now[:success] = "User saved successfully"
     sign_in user
     redirect_to user
  else
     flash.now[:error] = "Something went wrong: #{user.errors.full_messages}"
     render 'new'
  end
end

Well, after you run the create action – you should view the Pry session in the console, where your rails server is running.

So far so good, That’s it!!! See yar!!! :)

ActionPack Variants on Rails

ActionPack Variants on Rails

Rails 4.1 released a little while ago and came out with a fantastic new feature I think a lot of responsive web developers are going to flex. It’s called Variants. ActionPack Variants.

What does it do?
It allows you to create different views for different device formats - such as mobile phones, tablets and desktops.

1
2
3
# /app/views/home/index.html.erb
# /app/views/home/index.html+phone.erb
# /app/views/home/index.html+tablet.erb

Why is this useful?
This is tremendously useful because you can now serve a much slimmer version of your view to mobile devices, instead of just hiding the elements using CSS using media queries.

Hidden elements still load and need to come down ‘the wire’ - using Variants it’s much easier than before to serve up lean and mean views to mobile devices.

Setup
Create a homes controller that will enable you to play around with ActionPack Variants, run the commands below to create the home controller:

1
rails g controller homes show

Then apply a few simple routes to your application to finish setting things up. Open up your routes file (config/routes.rb).

1
2
root to: "homes#show"
resource :home, only: [:show]

Well, Now we are ready to play around with ActionPack Variants. ActionPack Variants works by using a before_action in your application controller. Open up your Application Controller (app/controllers/application_controller.rb) and modify so that it looks sometings like:

application_controller.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class ApplicationController < ActionController::Base
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :exception

  before_action :detect_browser

  private
    def detect_browser
      case request.user_agent
        when /iPad/i
          request.variant = :tablet
        when /iPhone/i
          request.variant = :phone
        when /Android/i && /mobile/i
          request.variant = :phone
        when /Android/i
          request.variant = :tablet
        when /Windows Phone/i
          request.variant = :phone
        else
          request.variant = :desktop
      end
    end
end

How does it work? Before an action is called, The detect_browser is called and the request.variant is set to whatever you want it to be. In the above example I use it determine whether we are running a mobile, tablet, or desktop device.

Then create a view called show.html+phone.erb (app/views/homes/show.html+phone.erb) for your homes controller and add in the code listed below:

show.html+phone.erb
1
2
3
4
<h1>Phone</h1>
<p>
  You are running on a smart phone.
</p>

Then create a view for our tablet users. Create a new view called show.html+tablet.erb (app/views/homes/show.html+tablet.erb) and add in the code listed below:

show.html+tablet.erb
1
2
3
4
<h1>Tablet</h1>
<p>
  You are running on a tablet.  Whoohoo!
</p>

Then modify your default show.html.erb (app/views/homes/show.html.erb) view. Open it up now and modify it so that it looks something like:

show.html.erb
1
2
3
4
<h1>Desktop</h1>
<p>
  All other users get redirected here.
</p>

There are still a few pieces of the puzzle left. What if you need to detect the device type prior to rendering the view? For example, setting paging size/options for our queries. Fortunately, this is pretty easy. Open up your homes controller (app/views/controllers/homes_controller.rb) and modify it so that it looks like the code listed below:

homes_controller.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class HomesController < ApplicationController
  def show
    @device = "others"
    respond_to do |format|

        format.html.phone do # phone variant
          # add code here for phones
        end

        format.html.tablet do # tablet variant
          # add code here for tablets
        end

        format.html.desktop do
          # add code here for desktops and other devices
        end
    end
  end
end

There is one more thing to do. What happens if you need to detect the variant in your view? Fortunately this is very easy and be shown,open up your application layout (app/views/layouts/application.html.erb) and modify it so that it looks like the code listed below:

application.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE html>
<html>
<head>
  <title>ActionPackVariantsExample</title>
  <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track' => true %>
  <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
  <%= csrf_meta_tags %>
</head>
<body>

<%= yield %>

<% if request.variant.include? :tablet %>
  <small>Welcome Tablet User</small>
<% elsif request.variant.include? :phone %>
  <small>Welcome Phone User</small>
<% end %>

</body>
</html>

Note the if statement starting with if request.variant.include? :tablet. Why do we use .include? The request.variant is actually an array. Therefore it is necessary to use .include?.

So far so good, That’s it! See ya! :)