ActiveRecord and Transactions!

If you ever have to do multiple actions with activerecord, you should group it into a transaction like so:

Post.transaction do
  posts.each do |post|
    post = Post.new(:body=>'Whatever')
    post.save!
  end
end

This will rollback too if the save fails.

Bulk update using ActiveRecord without SQL!

Here is a cool way you can update columns in a table without writing any SQL using ActiveRecord. Suppose you have a form with checkboxes that are for deleting posts for the ones that are checked:

<input name="posts[]" type="checkbox" value="<%= post.id %>" />

Now you can update this in the method of your controller that this form posts to:

Post.update_all({:removed=>true}, {:id=>params[:posts]})

ActiveRecord will take of the fact that you want to update 1 record or multiple!

ActiveRecord counting with associations

The other day I had to display the number of children items an object had so I decided to do the following:

# Controller
@customers = Customer.find(:all, :include=>[:receive_payments])

#View
<%= customer.receive_payments.count %>

While this worked for what I needed, it executed the following sql every iteration:

SELECT count(*) AS count_all FROM "receive_payments" WHERE ("receive_payments".customer_ref_list_id = E'850000-1071531366')

I thought this wasn’t right considering I used an association, however when you use count, it forces the use of count(*) on the database. This is where size comes in!!!!

<%= customer.receive_payments.size %>

Now we get the same results without the extra database counts!

Restful Authentication and Basic HTTP Auth

I had an application that was prompting a HTTP Authentication box in IE after using the restful authentication plugin. The way I fixed it was to replace the access_denied method in lib/authenticated_system.rb to:

def access_denied
  respond_to do |format|
    format.any do
      #format.html do
      store_location
      redirect_to new_session_path
    end
    #format.any do
      #  request_http_basic_authentication 'Web Password'
    #end
  end
end

Noticed I commented some lines out. This was so that if i ever need to revert, the code will still be there and I wont have to go looking for it. Hope this helps!

Rails route helpers – route_url vs route_path

If you weren’t already aware of this, there IS a difference between using route_url and route_path. Here are what they return:

<%= posts_url %>  # => http://localhost:3000/posts
<%= posts_path %> # => /posts

As a general rule of thumb, you would want to use posts_url in your controllers, and posts_path in your views.

href jumps to top of page

While this isn’t a ruby on rails specific issue, I do tend to do this a lot, and never thought twice about it, until it starts bugging the crap out of me. The issue is that you have a link that is used to do some type of javascript, instead of linking. So you add an onclick event, but you need something to link to. I usually put in a # sign:

Do Something

 
<%= link_to 'Do Something', '#', :onclick=>'dosomething()' %>

This is great, except that it jumps you to the top of the page. Very annoying. Here is the solution:

Do Something

 
<%= link_to 'Do Something', '#nogo', :onclick=>'dosomething()' %>

Notice I added “nogo” to my #. This will help prevent from jumping to the top of the page. You can of course use any text you want there.

Instant Rails Scaling through Asynchronous(Non-blocking) ActiveRecord

The guys over at NeverBlock have released a database adapter for Rails application that will severely increase the performance of ActiveRecord. Its also really easy to integrate into your application. Heres how: Add a line to environment.rb for mongrel or thin servers:

require 'never_block/servers/thin'

or

require 'never_block/servers/mongrel'

Change the adapter in database.yml:

adapter: neverblock_postgresql

or

adapter: neverblock_mysql

You can also specify the number of connections (default of 4):

connections: 12

More information, along with benchmarks, can be found here.

ActiveRecord conditions with association from hash

I’m sure you all know how to use the :conditions attribute when using ActiveRecord:

User.find(:all, :conditions=>['active = ?', true])

And you may even use associations this way:

User.find(
  :all,
  :include=>[:photos],
  :conditions=>['photos.removed = ? and users.active = ?', false, true]
)

But did you know that you can do this easier through hashes?

User.find(:all, :conditions=>{:active=>true})
User.find(
  :all,
  :include=>[:photos],
  :conditions=>{'photos.removed'=>false, 'users.active'=>true}
)

Nothing special there, but I thought it was pretty cool. One thing you have to remember when using associations, is to include that model.

Custom Rails Environments

Sometimes you need to create another environment for your rails application aside from development, test, production. In this example we will create a “stage” environment. Here is how you do it. First create the entry in your config/database.yml file:

# Stage database configuration
stage:
  adapter: sqlite3
  database: db/stage.sqlite3
  timeout: 5000

Next create a file called stage.rb and place it into config/environments. I usually just copy my development.rb file and then change the values as needed: Finally, In your config/environment.rb file, change the ENV[‘RAILS_ENV’] to:

ENV['RAILS_ENV'] ||= 'stage'

Now when you boot up your server or console, just specify the “stage” environment.

session[:current_user] = @user => BAD!

I’m sure most of you already would know this, or use restful authentication that handles it for you. However, if you have some custom setup where you are loading a user object, and then storing it in session, slap to you! Basically what I am talking about is doing this in your login method:

session[:current_user] = @user

Instead you should do:

session[:current_user] = @user.id

And then in your application controller, setup a before filter like so:

def set_current_user
  @current_user = User.find(session[:current_user])
end

One main reason not to do that would be if you had to update some user information. If you had it stored in session, then the user would have to log out and log back in for the changes to take effect. This is of course a basic rough draft, but you get the idea.