Notes posted to Ruby on Rails
RSS feedSTI - Making callbacks trigger in inherited classes
Assuming we have
class ParentClass < ActiveRecord::Base attr_accessible :type end class ChildClass < ParentClass after_save :perform_something end
Executing
ParentClass.create({:type => "ChildClass"})
will not trigger ChildClass callbacks. What is more, it will return instance of ParentClass instead of ChildClass.
To resolve this issue, you need to define following module
module ActiveRecord module CallbacksAwareSti extend ActiveSupport::Concern module ClassMethods def new(*args, &block) return super(*args, &block) unless args.first.respond_to?(:with_indifferent_access) type = args.first.with_indifferent_access[:type] if type.blank? or (type = type.constantize) == self super(*args, &block) else super(*args, &block).becomes(type) end end end end end
and include it in parent class
class ParentClass < ActiveRecord::Base include ActiveRecord::CallbacksAwareSti attr_accessible :type end
Inspired by http://stackoverflow.com/questions/4518935/activerecord-problems-using-callbacks-and-sti
block only and except
Code
class Journal < ActionController::Base # Require authentication for edit and delete. before_filter :authorize, :only => [:edit, :delete] # Passing options to a filter with a block. around_filter(:except => :index) do |controller, action_block| results = Profiler.run(&action_block) controller.response.sub! "</body>", "#{results}</body>" end private def authorize # Redirect to login unless authenticated. end end
Hidden Field Example
Here’s a pseudo code example of a hidden field within an ERB template. A post has many comments and this comment form is in a post’s show view. This would set a comment’s post_id attribute.
<%= form_for(@comment) do |f| %>
<%= f.hidden_field :post_id, :value => @post.id %>
<% end %>
method to use instead
This may be obvious, but the replacement for this method is csrf_meta_tags.
Example from Code School
module Tweets
class ShowPresenter extend ActiveSupport::Memoizable def initialize(tweet) @tweet = tweet end def username @tweet.user.username end def status @tweet.status end def favorites_count @tweet.favorites.count end memoize :username, :status, :favorites_count end end
HTML5 data- attributes using RESTful approach
HTML5 specifies extensible attributes like data-foo=“bar” (or as in Twitter Bootstrap data-toggle=“modal”), which poses two problems for Rails.
First, if you’re using symbol notation in link_to to specify attributes, this fails (dash is not a valid symbol character), so
Invalid!
link_to "Edit", @user, :class => "btn", :data-toggle => "modal"
There are two solutions:
-
put the symbols in quotes,
-
use the special :data hash
Solution 1: Quote Symbols
link_to "Edit", @user, :class => "btn", "data-toggle" => "modal"
Solution 2: Use the :data hash
link_to "Edit", @user, :class => "btn", :data => {:toggle => "modal"}
Resulting HTML
<a href="/users/1" class="btn", data-toggle="modal">Edit</a>
The second is minimally documented, but as a hash, can accept multiple values and is perhaps a little cleaner
I got it
Perfect match to work with attr_accessible
Locale
To change default locale by the parameter you can set :locale option, like below:
select_date 'user', 'birth', :locale => 'de'
Missed close tag
At the page http://apidock.com/rails/ActionView/Helpers/TagHelper/tag
<tt>.data()</tt> should be instead of <tt>.data()<tt>
Looks like this method has trouble with attributes:
ex:
require 'rubygems' require 'bundler' require 'active_support/core_ext' require 'pp' xml = '<test id="appears"> <comment id="doesnt appear"> it worked </comment> <comment> see! </comment> <comment /> </test>' hash = Hash.from_xml(xml) pp hash #=>{"test"=>{"id"=>"appears", "comment"=>["it worked", "see!", nil]}} # Notice how the id attribute on the first comment element doesn't appear.
Options select_hour
In my view I wanted to do this <%= select_hour(@hour, :start => 8, :end => 12) %> but did not work. I looked at the documentation and have not seen anything like it. http://api.rubyonrails.org/classes/ActionView/Helpers/DateHelper.html#method-i-select_hour
So I studied how it worked this helper. http://api.rubyonrails.org/classes/ActionView/Helpers/DateHelper.html#method-i-select_hour develop and achieve this:
the helper application:
module DataAnnouncementsHelper
class HelperDate < ActionView::Helpers::DateTimeSelector def select_hour if @options[:use_hidden] || @options[:discard_hour] build_hidden(:hour, hour) else build_options_and_select(:hour, hour, :end => @options[:end], :start => @options[:start], :ampm => @options[:ampm]) end end end def select_hour(datetime, options = {}, html_options = {}) HelperData.new(datetime, options, html_options).select_hour end
end
The view:
<%= select_hour(@hour, :start => 8, :end => 12) %>
Where @hour = 10 the result is:
<select id=“date_hour” name=“date[hour]”>
<option value="08">08</option> <option value="09">09</option> <option value="10" selected="selected">10</option> <option value="11">11</option> <option value="12">12</option>
</select>
JQuery script for dynamically adding and removing fields_for
I like drogus idea. But I wanted a cleaner one, so I created an unobtrusive JQuery script to have the same functionality.
Example Usage:
<%= form_for @post do |form| %> Title: <%= form.text_field :title %> Body: <%= form.text_field :body %> Tags: <div id="tag-list"></div> <div class="numerous"> <div class="numerous-form"> <%= form.fields_for :tag, Tag.new, :child_index => "replace_this" do |f| %> <%= f.text_field :name %> <%= f.hidden_field :_destroy, :value => 0, :class => "numerous-remove-field" %> <%= link_to "delete", "#", :class => "numerous-remove" %> <% end %> </div> <%= link_to "add tag", "#", :class => "numerous-add", :id => "for-tag-list" %> </div> <% end %>
See script at: http://github.com/kbparagua/numerous.js
Disable layout on ajax
In actions that may or may not be loaded via ajax I use:
render :layout => !request.xhr?
For an entire controller I might use something like:
layout :has_layout? private def has_layout? request.xhr? ? false : controller_name end
What seems unusual is that
layout true
will try look for the layout true.erb
Replaced by
replaced by “class_attibute”: http://apidock.com/rails/v3.2.1/Class/class_attribute
Replaced by
replaced by “class_attibute”: http://apidock.com/rails/v3.2.1/Class/class_attribute
Makes it possible to use a scope through an association
This is a very useful method if you want to to use a scope through an association:
class Book < ActiveRecord::Base scope :available, where(:available => true) end class Author < ActiveRecord::Base has_many :books scope :with_available_books, joins(:books).merge(Book.available) end # Return all authors with at least one available book: Author.with_available_books
See http://asciicasts.com/episodes/215-advanced-queries-in-rails-3 for more info.
Example to auto download
Controller
op = Operation.find(params[:id]) fname = "operation_#{op.id}_#{DateTime.now.to_i}.csv" send_data op.export(params[:url_type]), :type => 'text/csv; charset=iso-8859-1; header=present', :disposition => "attachment; filename=#{fname}.csv"
export_csv
def export(url_type) csv_data = CSV.generate do |csv| csv << self.header_columns # simple array ["id","name"] url_items = @operation.url_items.where(:url_type => url_type) url_items.each do |url_item| csv << self.process_row(url_item) # simple array [1,"bob"] end end return csv_data end
Use exist scopes on default_scope - pay attention
To use exists scopes on default_scope , you can use something like:
class Article < ActiveRecord::Base scope :active, proc { where("expires_at IS NULL or expires_at > '#{Time.now}'") } scope :by_newest, order("created_at DESC") default_scope by_newest end
But, if you would add a filter, and it require a lazy evaluate, use block on default_scope declaration, like:
default_scope { active.by_newest }
Deprecation in 3.1+
In Rails 3.1 and higher, just use ruby’s SecureRandom, e.g.
Before
ActiveSupport::SecureRandom.hex
After
SecureRandom.hex
Deprecated proxy_owner
Just change your
proxy_owner
calls to
@association.owner
Found it here: http://mileszs.com/deprecation-warnings-for-proxyowner-in-rails
Add html5 scriipt async attribute
http://www.w3schools.com/html5/att_script_async.asp
javascript_include_tag "application", :async => true
flash messages
In rails 3.1 the following does not work for me
redirect_to { :action=>'atom' }, :alert => "Something serious happened"
Instead, you need to use the following syntax (wrap with parens)
redirect_to({ :action=>'atom' }, :alert => "Something serious happened")
Example of conditions using
f.e.
validates :number, :presence => { :if => :quota_file? } def self.quota_file? quota_file? end
won't refresh updated_at
This will not cause :updated_at column to refresh, while ActiveRecord::Base#increment! would.
looking to bypass validations, callbacks and updated_at?
Take a look at updated_column
http://apidock.com/rails/ActiveRecord/Persistence/update_column


