Couple good old usefull Rails ActiveRecord's methods

posted on Tuesday, June 29, 2010

This will increment "views" attribute of the post and save it to database, increment!(attribute, by=1):

@post.increment!(:views)

This will decrement "views" attribute of the post and save it to database, decrement!(attribute, by=1):

@post.decrement!(:views)

This will assign to attribute the boolean opposite of it:

@post.published # -> true
@post.toggle!(:published)
@post.published # -> false
class PostsController < ApplicationController
  before_filter :find_post, :only => [:publish, :show]
  def show
    @post.increment!(:views)
  end
  private
    def find_post
      @post = Post.find(params[:id])
    end
end

Reloading attributes from database, to get the latest values, reload(options = nil):

@post = user.posts.find(5)
user.posts.find(5).increment!(:views)
@post.views # -> 0
@post.reload
@post.views # -> 1

Reordering of already defined scope:

Post.scoped.collect {|p| p.id }
- 1
- 2
- 3
Post.scoped.reverse_order.collect {|p| p.id }
- 3
- 2
- 1
Continue reading

Rails fragment caching

posted on Thursday, June 24, 2010

Simple fragment caching example:

<% cache do %>
  Something here ...
<% end %>

Or if you want to specify action name and suffix of this cache block:

<% cache(:action => 'index', :action_suffix => 'all') do %>
  Something here ...
<% end %>

Maybe it's not the best way to handle cached fragment names but i prefer using this kind of key:

<% cache('top#posts#') do %>
  top posts block content ...
<% end %>

where 'top' is just a key of this cached fragment, but #posts# is used as identifier for the type of content, so for example we have 3 cached blocks, and they are not related to one controller or action:

  • top#posts#
  • recent#posts#
  • something_else#posts#

When new post was created or deleted, instead of specifying expire_fragment for each cache key, you just add one line to your sweeper or observer or wherever you specify your expiring:

expire_fragment %r{#posts#}

And after that all cached blocks that related to posts are expired, its usefull when you have lots of fragments which are loaded from different controllers and actions and placed all over the website. The result of this is you'll never mess up with key names of your fragments, and will be sure that your cache is always up to date.

Continue reading

Manage html titles with rails

posted on Tuesday, June 01, 2010

Here is some ways to manage html titles, keywords and description to have a seo friendly website:

Lazy way is to use an instance variable, which has a default value and you could override it in any controller's action:

controllers/posts.rb :

def index
  @title = "Index title"
end

views/posts/index.html.erb :

<%=@title ||= "Default title"%>

If there is not too many pages on the website its better to use a helper with all titles and descriptions you need, to keep controllers clean from that kind of stuff. Also this method works good for those who want to have all their titles, descriptions etc. in one place to track it very easily.

helpers/application_helper.rb :

def title
  titles = {
    :blog => {
      :index => "Index title", 
      :default => "Any other action title"
    }, 
    :users => {
      :index => "Index title", 
      :show => "Show title", 
      :default => "Any other action title"
    }, 
    :default => "Default title"
  }
  c = params[:controller].to_sym
  a = params[:action].to_sym
  return titles[c] ? titles[c][a] ? titles[c][a] : titles[c][:default] : titles[:default]
end

views/layouts/application.html.erb :

<%=@title || title%>

Another one is content_for method, which probably is the best for 90% of websites:

views/layouts/application.html.erb :

<%= yield(:title) || "Default title" %>

views/posts/index.html.erb :

<%= title "Page title" %>

helpers/application_helper.rb :

def title html_title
  content_for :title do
    html_title
  end
end

It's a good idea to move titles, description and keywords out from controllers because it is entirely a view responsibility even if you need them to be dynamicly made with user names or post tags.

Continue reading