Pages

Showing posts with label Ruby on Rails. Show all posts
Showing posts with label Ruby on Rails. Show all posts

Tuesday, January 17, 2017

Includes vs Joins in Rails: When and where?

The most important concept to understand when using includes and joins is they both have their optimal use cases. Includes uses eager loading whereas joins uses lazy loading, both of which are powerful but can easily be abused to reduce or overkill performance.
If we first take a look at the Ruby on Rails documentation, the most important point made in the description of the includes method is:
With includes, Active Record ensures that all of the specified associations are loaded using the minimum possible number of queries.
In other words, when querying a table for data with an associated table, both tables are loaded into memory which in turn reduce the amount of database queries required to retrieve any associated data. In the example below we are retrieving all companies which have an associated active Person record:

@companies = Company.includes(:persons).where(:persons => { active: true } ).all
@companies.each do |company|
     company.person.name
end

Saturday, December 19, 2015

Understanding the Rails Authenticity Token

What happens

When the user views a form to create, update, or destroy a resource, the Rails app creates a random authenticity_token, stores this token in the session, and places it in a hidden field in the form. When the user submits the form, Rails looks for the authenticity_token, compares it to the one stored in the session, and if they match the request is allowed to continue.

Why it happens

Since the authenticity token is stored in the session, the client cannot know its value. This prevents people from submitting forms to a Rails app without viewing the form within that app itself. Imagine that you are using service A, you logged into the service and everything is ok. Now imagine that you went to use service B, and you saw a picture you like, and pressed on the picture to view a larger size of it. Now, if some evil code was there at service B, it might send a request to service A (which you are logged into), and ask to delete your account, by sending a request to http://serviceA.com/close_account. This is what is known as CSRF (Cross Site Request Forgery).

Thursday, July 9, 2015

Send PDF attachments from Rails with WickedPdf and ActionMailer

In almost any web application you create, the question of generating PDF files will pop up pretty soon. 

Setup

As always, using a ruby gem in rails is pretty simple, you just add a couple of lines to the Gemfile
gem 'wicked_pdf'
#we need the new binary here, so that we can be OS independent
gem 'wkhtmltopdf-binary', github: 'pallymore/wkhtmltopdf-binary-edge', tag: 'v0.12.2'

Usage

This setup will work pretty straightforward in the controllers, because WickedPdf registers :pdf request format, and you can respond to it in the same fashion as html or js in a respond_to block. Code below is copied from the WickedPdf Readme page.

Monday, June 1, 2015

Check if ActiveRecord object is valid with params before updating to Database

To update the attributes without saving them, you can use
@obj.assign_attributes( params[:obj] )
Then to check if the object is valid, you can call
@obj.valid?
If the object is not valid, you can see the errors (only after calling .valid?) by calling
@obj.errors
If the object is valid, you can save it by calling
@obj.save
However, all of this usually isn't necessary. If the object isn't valid, then ActiveRecord won't save the object to the database, so all of the attribute changes are forgotten when you leave the controller action.
Also, since an invalid record won't be saved to the database, you can always just call Object.find() again to get the original object back.

Thursday, March 12, 2015

Access WEBrick from a different PC

By using the below command, One can access webrick from different PC

rails s -b IP_ADDRESS -p PORT

Wednesday, December 3, 2014

Adding Password Complexity Validations To Devise

Here we have a typical Devise user model. What’s new is the password complexity validation.
class User < ActiveRecord::Base
  devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable
  attr_accessible :email, :password, :password_confirmation, :remember_me,

  validate :password_complexity

  def password_complexity
    if password.present? and not password.match(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d). /)
      errors.add :password, "must include at least one lowercase letter, one uppercase letter, and one digit"
    end
  end
end

Friday, November 21, 2014

Simple, user-friendly cancel links for your Rails forms



The default Rails view generator includes back links on form-related view templates, so if users change their mind they can easily get out of the form and on to something else. However, these links are static. What do you do if you allow users to access the form from multiple views (say, an index and a show).
Here’s a simple but effective solution I came up with: Instead of passing a static URL, I pass the HTTP referrer environment variable as the location. That way users are taken back to the page from which they opened the form to begin with.
Here’s how it works. Most of the code resides in the application_helper.rb file:
  module ApplicationHelper
    include Rails.application.routes.url_helpers

    def cancel_link
      return link_to 'Cancel', request.env["HTTP_REFERER"], 
        :class => 'cancel', 
        :confirm => 'Are you sure? Any changes will be lost.'
    end
  end
You’ll need to include Rails.application.routes.url_helpers in order to access link_to from a helper method. Then you add the helper method itself, which does nothing more than return a cancel link. Mine uses an old-style :confirm message; you can spruce it up with some less obtrusive if you’d like.
If I need a cancel link in a view, I just add
  <%= cancel_link %>
The result: a flexible, reusable cancel option that’s much more user-friendly.

Thursday, January 30, 2014

API Upload with CarrierWave

 I want to share a quick snippet with regards to a problem I had a few months ago: How to upload a picture/file to a Ruby on Rails project, which is utilizing CarrierWave to handle the upload mechanism, by utilizing the direct POST call.
With this comes at least two challenges:
  • You cannot insert a file directly into a JSON object;
  • CarrierWave does not support uploading a file which is not uploaded using a form object.
Solving the first problem is almost trivial, you simply encode the file into Base64 and pass it along, but the second problem requires a little more work. What I did to solve it was to decode the Base64 string into a temp file, and then create a new uploaded file from that temp file.

Saturday, January 11, 2014

Fixing readline for the Ruby on Rails console

have begun trying out the Ruby on Rails framework. While doing so I got stuck at a very early stage in thedocumentation.
$ rails console
/home/tobias/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/irb/completion.rb:9:in `require': no such file to load -- readline (LoadError)
from /home/tobias/.rvm/rubies/ruby-1.9.2-p18080/lib/ruby/1.9.1/irb/completion.rb:9:in `<top (required)>'
from /home/tobias/.rvm/gems/ruby-1.9.2-p180/gems/railties-3.0.9/lib/rails/commands/console.rb:3:in `require'
from /home/tobias/.rvm/gems/ruby-1.9.2-p180/gemsems/railties-3.0.9/lib/rails/commands/console.rb:3:in `<top (required)>'
from /home/tobias/.rvm/gems/ruby-1.9.2-p180/gems/railties-3.0.9/lib/rails/commands.commandsrb:20:in `require'
from /home/tobias/.rvm/gems/ruby-1.9.2-p180/gems/railsilties-3.0.9/lib/rails/commands.rb:20:in `<top (required)>'
from scriptt/rails:6:in `require'
from script/rails:6:in `<main>'
The problem is that Ruby is somehow not cofigured to load the readline library and thus cannot run its console. This is a downside of using a language specific package manager, seperate from your operating system's package manager.

Friday, January 10, 2014

Rails- :dependent => :destroy VS :dependent => :delete_all

In rails guides it's described like this:
Objects will be in addition destroyed if they’re associated with :dependent => :destroy, and deleted if they’re associated with :dependent => :delete_all
But what's the difference between being destroyed and being deleted?
The difference is with callback.
The :delete_all, made directly in your application the delete by SQL :
DELETE * FROM users where compagny_id = XXXX
With the :destroy, there are an instantiation of all of you children. 
So, if you can't destroy it or if each has their own :dependent, its can be called.

Use after_commit instead of active record callbacks to avoid unexpected errors

AR callbacks after_create/after_update/after_destroy to generate background job etc are useful, but these callbacks are still wrapped in database transaction, and you may probably get unexpected errors on production servers.
Before It’s common to generate a background job to send emails like
class Comment < ActiveRecord::Base
  after_create :asyns_send_notification
  def async_send_notification
    Notifier.send_new_comment_notification(self).deliver
  end
 handle_asynchronously :async_send_notification
end

# It looks fine that comment record passed to delayed job and then delayed job will fetch this
#comment and then post on which this comment has been made and a notification will
#send via email to the author of that post. Right?
You won’t see any issue in development, as local db can commit fast. But in production server, db traffic might be huge, worker probably finish faster than transaction commit. e.g
  1. main process
  2. worker process
  3. BEGIN
     INSERT comment in comments table
     # return id 10 for newly-created notification
     SELECT * FROM notifications WHERE id = 10
     COMMIT
    
In this case, the worker process query the newly-created notification before main process commits the transaction, it will raise NotFoundError, because transaction in worker process can’t read uncommitted notification from transaction in main process.
Refactor
So we should tell activerecord to generate notification worker after notification insertion transaction committed.
class Comment < ActiveRecord::Base
after_commit :asyns_send_notification,:on => :create  # This is the main point of the whole thing.

  def async_send_notification
    Notifier.send_new_comment_notification(self).deliver
  end
 handle_asynchronously :async_send_notification
end
Now the transactions order becomes
  1. main process
  2. worker process
  3. BEGIN
     INSERT comment into comments_table
     return id 10 for newly-created notification
     COMMIT
     SELECT * FROM notifications WHERE id = 10
    
Worker process won’t receive NotFoundErrors any more. :)
For More Details visit http://www.codebeerstartups.com

Tuesday, January 7, 2014

Multiple submit buttons for the same form in Rails

You can create multiple submit buttons and provide a different value to each:
<% form_for(something) do |f| %>
    ..
    <%= f.submit 'A' %>
    <%= f.submit 'B' %>
    ..
<% end %>
This will output:
<input type="submit" value="A" id=".." name="commit" />
<input type="submit" value="B" id=".." name="commit" />
Inside your controller, the submitted button's value will be identified by the parameter commit. Check the value to do the required processing:
def <controller action>
    if params[:commit] == 'A'
        # A was pressed 
    elsif params[:commit] == 'B'
        # B was pressed
    end
end
However, remember that this tightly couples your view to the controller which may not be very desirable.

Not Equal support for Active Record queries in Rails 4

The Active Record query interface for the most part abstracts SQL from the developer. However, there is a condition that always requires using pure string conditions in awhere clause: <> or !=, depending on the database. Starting in Rails 4, query method not has been added to rectify this.

Example

Let's look at an example of executing the new not query method. First we will look at how it was done in Rails 3, and then look at how Rails 4 handles the same problem. All examples will be querying against an Article model with a title field. The examples below will be using a SQLite database.

The Rails 3 Way

Article.where("title != ?", params[:title])

The Rails 4 Way

To use the new query method, it must be chained to a where clause with no arguments:
Article.where.not(title: 'Rails 3')
# >> SELECT "articles".* FROM "articles" WHERE ("articles"."title" != 'Rails 3')
The not query method can also accept an array to ensure multiple values are not in a field:
Article.where.not(title: ['Rails 3', 'Rails 5'])
# >> SELECT "articles".* FROM "articles" WHERE ("articles"."title" NOT IN ('Rails 3', 'Rails 5'))

Monday, January 6, 2014

New HTML5 Form Input Helpers for Rails4

In this post, we are going to take a look at the new HTML5 Form Helpers being added into Rails 4. While we are only covering the model object helper versions that are used with form_for, each form helper below also has a corresponding tag helper. For example, if we are talking about week_field, there is a tag helper week_field_tag that can be used withform_tag.

week_field

The week_field form helper creates an input of type "week", that sets a week without any timezone information. A week is represented by four digits for the year, followed by -W, and ending with two digits representing the week number. For example, the current week of this post would be 2012-W50.
The week_field form helper accepts three options: :min:max, and :step:
  • :min: The minimum acceptable value
  • :max: The maximum acceptable value
  • :step: The acceptable value granularity
Here is an example of a week_field being set with optional minimum and maximum week constraints:
<%= f.week_field :week,
  min: Time.zone.today.beginning_of_year,
  max: Time.zone.today.end_of_year %>

Register your own flash types - Rails 4

In Rails 3, the ability to set flash parameters :notice and :alert in a controllerredirect_to call was added. Along with this change,ActionController::Base#notice andActionController::Base#alert were added as convenience accessors, which mapped to flash[:notice] and flash[:alert] respectively.
To set a custom flash type in your controller, you would have add the key/value pair to the controller flash hash, or you could also pass a hash to the optional :flashoption in redirect_to.
As of Rails 4, developers will have the ability to register their own flash types by using the new ActionController::Flash.add_flash_types macro style method.

The Rails 3 Way

Here is an example of setting a custom error flash type in Rails 3:
# app/controllers/users_controller.rb
class UsersController < ApplicationController
  def create
    ...
    flash[:error] = "An error message for the user"
    redirect_to home_path
  end
end

# app/views/home/index
<%= flash[:error] %>

The Rails 4 Way

Here is the same example as above, using Rails 4:
# app/controllers/application_controller.rb
class ApplicationController
    ...
  add_flash_types :error, :another_custom_type
end

# app/controllers/users_controller.rb
class UsersController < ApplicationController
  def create
    ...
    redirect_to home_path,
      error: "An error message for the user"
  end
end

# app/views/home/index
<%= error %>

Saturday, January 4, 2014

Migration to rename an ActiveRecord model and its table in Rails

In Rails 3.1+ ActiveRecord::Migration::CommandRecorder knows how to reverse rename_table migrations, so you can do this:
class RenameOldTableToNewTable< ActiveRecord:Migration
    def change
        rename_table :old_table_name, :new_table_name
    end 
 end
You need to rename the model declaration files manually.

Routing Concerns - Rails 4

The Rails config/routes.rb file encapsulates all the mappings from URLs to controller actions. Over the years, helpful additions have been added to slim this file down so that as developers, we can stop repeating ourselves. One example of this was the routing method resources, which maps four named routes to seven controller actions based on the HTTP request method.
As of Rails 4, routing concerns have been added to the router. Routing concerns allows you to declare common routes, which can be mixed into other resources and routes.

Example

A common example of duplication in the config/routes.rb file happens when a polymorphic association is nested under a parent resource.

Friday, January 3, 2014

nil vs empty vs blank in Ruby on Rails

.nil?
.nil? can be used on any object and is true if the object is nil.
.empty?
.empty? can be used on strings, arrays and hashes and returns true if:
  • String length == 0
  • Array length == 0
  • Hash length == 0
Running .empty? on something that is nil will throw a NoMethodError.
.blank?
That is where .blank? comes in. It is implemented by Rails and will operate on any object as well as work like .empty? on strings, arrays and hashes.
nil.blank? == true
false.blank? == true
[].blank? == true
{}.blank? == true
"".blank? == true
5.blank? == false
.blank? also evaluates true on strings which are non-empty but contain only whitespace:
"  ".blank? == true
"  ".empty? == false
Rails also provides .present?, which returns the negation of .blank?.