Recent good notes
RSS feedTo throw an exception, use Kernel#raise
Other languages use the term throw for raising exceptions, but Ruby has a specific raise call for that.
Do not forget to add indexes
Don’t forget to add indexes to HATM table:
add_index :developers_projects, [:developer_id, :project_id]
strip_tags method not functioning in controllers, models, or libs
It comes up with an error about white_list_sanitizer undefined in the class you’re using it in. To get around this, use:
ActionController::Base.helpers.strip_tags('string')
To shorten this, add something like this in an initializer:
class String def strip_tags ActionController::Base.helpers.strip_tags(self) end end
then call it with:
'string'.strip_tags
sanitize method not functioning in controllers, models, or libs
It comes up with an error about white_list_sanitizer undefined in the class you’re using it in. To get around this, use:
ActionController::Base.helpers.sanitize('string')
To shorten this, add something like this in an initializer:
class String def sanitize ActionController::Base.helpers.sanitize(self) end end
then call it with:
'string'.sanitize
Corrected link to ActiveRecord's "new_record?" method
rafaelrosafu, the correct tink to ActiveRecord’s “new_record?” method is:
"http://apidock.com/rails/ActiveRecord/Base/new_record%3F"
Parameters for Hash#inject
When running inject on a Hash, the hash is first converted to an array before being passed through.
The typical Enumerable#inject approach would be to simply capture the value:
array.inject(...) do |c, v| end
In the case of a Hash, v is actually a key/value pair Array. That is the key is v.first and the value is v.last, however using the pair this way is awkward and can lead to confusion.
Better to simply expand the parameters in the block definition:
hash.inject(...) do |c, (k, v)| end
Where c is the traditional carry variable and k/v represent key and value respectively.
Example
This function can be used to pass the ID of selected item, for example:
# with select or collection_select helpers: { :onchange => remote_function(:url => { :action => 'do_smth' }, :with => "'id=' + $('the_id').value") } # and grab ID in controller action as usually: YourModel.find(params[:id])
Define handlers in order of most generic to most specific
The later the definition of the rescue handler, the higher the priority:
rescue_from Exception, :with => :error_generic rescue_from Exception::ComputerOnFire, :with => :panic
Declaring the Exception catch-all handler last would have the side-effect of precluding any other handlers from running.
This is what is meant by being “searched…from bottom to top”.
Method has moved to ActionController::Rescue::ClassMethods module
This method has simply moved, still works the same way in 2.3+
New location: ActiveSupport::Rescuable::ClassMethods#rescue_from
Setting child_index while using nested attributes mass assignment
When using nested attributes mass assignment sometimes you will want to add new records with javascript. You can do it with pure javascript, but if HTML is long your javascript will be long and messy and it will not be DRY as probably you already have a partial for it.
So to add a partial dynamically you can do something like that (notice string “index_to_replace_with_js”):
link_to_function
def add_object_link(name, form, object, partial, where) options = {:parent => true}.merge(options) html = render(:partial => partial, :locals => { :form => form}, :object => object) link_to_function name, %{ var new_object_id = new Date().getTime() ; var html = jQuery(#{js html}.replace(/index_to_replace_with_js/g, new_object_id)).hide(); html.appendTo(jQuery("#{where}")).slideDown('slow'); } end
js method in one of helpers (from minus mor plugin)
def js(data) if data.respond_to? :to_json data.to_json else data.inspect.to_json end end
This method will generate link adding generated partial to html.
The thing that is not mentioned in docs is how to set child_index. You must add it as an argument in hash.
Example of partial
<% form.fields_for :tasks, task, :child_index => (task.new_record? ? "index_to_replace_with_js" : nil) do |tasks_form| %> <% tasks_form.text_field :name %> <% end %>
Using add_object_link
<% form_for :project do |form| %> <div id="tasks"> <%# displaying existing tasks %> </div> <%= add_object_link("New task, form, Task.new, "task", "#tasks") %> <% end %>
Thanks to child_index after insertion it will change indexes to current time in miliseconds so added tasks will have different names and ids.
Superclass of OrderedHash
Note that in Rails 2.3, OrderedHash changed from being a subclass of Array to a subclass of Hash. This is contrary to what the documentation says above.
HTML entities in options
Unfortunately everything is escaped with ERB::Util#html_escape. Your only option is either manually construct options or compeletely overwrite this method.
Array clustering
Sometimes you don’t want to mangle sequence of an array and just want to group adjacent values. Here’s a nice method to do so (drop it in your initializers directory or something):
module Enumerable # clumps adjacent elements together # >> [2,2,2,3,3,4,2,2,1].cluster{|x| x} # => [[2, 2, 2], [3, 3], [4], [2, 2], [1]] def cluster cluster = [] each do |element| if cluster.last && yield(cluster.last.last) == yield(element) cluster.last << element else cluster << [element] end end cluster end end
Similarly you can do the clustering on more complex items. For instance you want to cluster Documents on creation date and their type:
Document.all.cluster{|document| [document.created_on, document.type]}
Take care when writing regex
When you want to validate a field for a continuous string you’d probably write something like this (if it’s really early in the morning and you didn’t have your coffee yet):
validates_format_of :something => /\w/
At the first sight it looks like it’s working because something = “blahblahblah” is valid. However, so is this: something = “blah meh 55”. It’s just that your regex matched a substring of the value and not the whole thing. The proper regex you’re looking for is actually:
validates_format_of :something => /^\w$/
Assets hosts
You can also setup assets hosts in enviroments:
config.action_controller.asset_host = "http://your-assets-server.com"
The docs are in AR::Base
The docs you’re looking for are in ActiveRecord::Base
Ordering of format blocks is important
The order in which your format blocks appear, like:
format.html { } format.js { }
are used to infer priority in cases where the appropriate format is ambiguous.
Sorting Hashes with Symbol Keys
To sort a hash with symbol keys, use Enumerable#sort_by:
h = { :a => 20, :b => 30, :c => 10 } h.sort # => NoMethodError: undefined method `<=>' for :a:Symbol h.sort_by { |k,v| k.to_s } # => [[:a, 20], [:b, 30], [:c, 10]]
Override fieldWithErrors markup in Rails > v2
The code posted by @hosiawak will still work in recent versions of Rails, but maybe a more current, idiomatic way to do it is to stick this inside the Rails::Initializer block in environment.rb (obviously you’ll also need to restart your server to pick up the config change):
config.action_view.field_error_proc = Proc.new {|html_tag, instance| %(<span class="fieldWithErrors">#{html_tag}</span>)}
Hour with/without preceding zero
One gotcha is the difference between the hour in 12 hour time with and without a preceding zero. In some fonts they look the same.
With preceding zero (capital I)
Time.now.strftime("%I:%M") # => 05:21
Without preceding zero (lowercase L)
Time.now.strftime("%l:%M") # => 5:21
Usage
Here’s how to use it, just so it’s perfectly clear:
skip_before_filter :method_to_skip, :only => [:method_name]
multiple filter example
actually you can have it even shorter with:
before_filter :authorize, :set_locale, :except => :login
So, how do you enable db sessions?
First, run:
rake db:sessions:create
Then, run your pending migrations. This will create the migration you need to run in order to create the sessions table.
Second, go into config/environment.rb and uncomment or put in:
config.action_controller.session_store = :active_record_store config.action_controller.session = { :session_key => '_your_session_name_here', :secret => 'SOME_CRYPTOGRAPHICALLY_SECURE_KEY' }
Third, get yourself a secure key with:
rake secret
And finally, paste your new key into the :secret above.
Passing optional arguments with defaults to a named_scope
An easy way to do this. (This also shows how you can use joins in a named_scope as well.)
Class User << ActiveRecord::Base belongs_to :semester named_scope :year, lambda { |*year| if year.empty? || year.first.nil? { :joins => :semester, :conditions => ["year = #{CURRENT_SEMESTER}"]} else { :joins => :semester, :conditions => ["year = #{year}"]} end } end
You can then call:
User.year # defaults to CURRENT_SEMESTER constant User.year() # same as above User.year(nil) # same as above; useful if passing a param value that may or may not exist, ie, param[:year] User.year(2010)
Use helpers in your ActionMailer views
It’s very easy to give your mailer access to helpers:
# Let your mailer user the ApplicationHelper methods class MyMailer < ActionMailer::Base helper :application end
Use the current URL, with changes
You can use the current URL, whatever it is, with changes, as in:
# Create a link to the current page in RSS form url_for(:overwrite_params => {:format => :rss})
This can be super-helpful because it preserves any GET params (like search parameters)
Better autopad numbers
There is a much better way than to use diwadn’s method if you want to pad numbers with zeros. Here’s my recommended way to do it:
"Number: %010d" % 12345 #=> "Number: 0000012345"
It’s very easy. First we begin our placeholder with “%”, then we specify a zero (0) to signify padding with zeros. If we omitted this zero, the number would be padded with spaces instead. When we have done that, just specify the target length of the string. At last a single “d” is placed to signify that we are inserting a number.
Please see String#% and Kernel#sprintf for more information about how to do this.
Here’s another example of how to do it:
12345.to_s.rjust(10, "0") #=> "0000012345"
See String#rjust for more information.
Any of these methods are a lot better than the method outlined below.
More Information
More information can be found at ActionController::Verification::ClassMethods
User a block to extend your associations
You can use blocks to extend your associations with extra methods.
code sample
has_many :children, :dependent => :destroy do def at(time) proxy_owner.children.find_with_deleted :all, :conditions => [ "created_at <= :time AND (deleted_at > :time OR deleted_at IS NULL)", { :time => time } ] end end Model.children.each # do stuff Model.children.at( 1.week.ago ).each # do old stuff
you must use ‘proxy_owner’ to link back to your model.