Notes posted to Ruby on Rails
RSS feedSetting 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.
Translations of label method
The label method won’t use your translated attribute names - which seems like big disadvantage of this method.
For a quick workaround, try using this in a helper:
def label(object_name, method, text = nil, options = {}) text ||= object_name.classify.constantize.human_attribute_name(method.to_s) ActionView::Helpers::InstanceTag.new(object_name, method, self, options.delete(:object)).to_label_tag(text, options) end
I didn’t properly test this, but it seems to work.
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
Patch looks good.
I assume commenting right below the ticket is the “+1” action? :) Thanks for the reply and patch efforts!
Exension module patch
I’d say its just an oversight.
If you’d like to see all associations get equal support for extension modules take a look at this patch and give it a +1.
Why such inconsistency on 'extend' design?
Thanks for the great note! Finally… it took me quite some time to find this page and track down why there is such inconsistency between belongs_to and, say, has_many, proxy extension design. Do you (or anyone knowledgeable here) know the reason behind such design inconsistency? It’s quite annoying (and quite abstraction- and documentation-defeating) that one has to look this deep into the source code to see what’s going on.… Thanks!
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.
Deprecated
This method is now at ActiveSupport::CoreExtensions::Module#alias_method_chain
Reconfiguring the Rails cleaner
The Rails cleaner is available from the top-level Rails class:
Rails.backtrace_cleaner
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>)}
Usage
Here’s how to use it, just so it’s perfectly clear:
skip_before_filter :method_to_skip, :only => [:method_name]
Deprecated - replacement method
The description rightly lists this as deprecated, but using it will still work atm, as it seems to have moved to ActiveSupport::CoreExtensions::Module instead.
So your code should still work.
multiple filter example
actually you can have it even shorter with:
before_filter :authorize, :set_locale, :except => :login
Gotcha with method calls inside select loop
Keep in mind that any methods you call on the object in the select loop will be strung together when the Javascript is rendered. For example:
page.select(".shipping_type_fee").each do |td| td.down("span").update("--").show td.down("img").hide end
will be rendered as:
$$('.shipping_type_fee').each(function(value, index) { value.down("span").update("--").show().down("img").hide(); });
This is probably not what you want!
No documentation here…
…but you’re probably looking for ActionController::RequestForgeryProtection::ClassMethods
usage helper with block
helper example
def my_helper(&block) inner = capture(&block) out = "<somehtml>#{inner}</somehtml>" block_called_from_erb?(block) ? concat(out) : out end
view example
<% my_helper do %> sometext <% end %>
output
<somehtml>sometext</somehtml>
alternative
not sure but block_called_from_erb? seems to be the replacement
if you get NameError: uninitialized constant ActionController::Caching::Sweeper
I got hit with this on an upgrade. Had a reference to ApplicationController::Base in development.rb (prod as well) which caused this problem http://rails.lighthouseapp.com/projects/8994/tickets/1977
Fix was to remove the loading of ApplicationController::Base and put it in an initializer (where it should have been).
Content_tag in helpers
Content_tag works great in a helper and is a nice way to clean up your views.
If you’re returning more than one content_tag you’ll need to concat them:
@content = content_tag(:tr, "first item") @content << content_tag(:tr, "second item")
Be mindful that when doing the above, you must use parentheses around the content_tag options. In the above example, content_tag :tr, “second item” will return an error.
Finding all records WITHOUT associations
(Thanks to someone on the rails IRC channel who gave me this tip.)
Where Users and Events have a habtm relationship, to find all Users that have no events:
User.find(:all, :include => :events, :conditions => { "events_users.event_id" => nil})
(Note that when specifying a condition on a joined table, you have to put the field name in a string rather than a symbol. In the above example, :events_users.event_id will not work.)
New and improved version
As this method is now deprecated, check the documentation for the new version (adds some more options), which gets included via a module:
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.
Generating empty conditions
In some cases, you might find it useful for your lamba to generate empty conditions based on the passed parameter.
Class Article << ActiveRecord::Base named_scope :category, lambda { |cat| if cat == :all { :conditions => {} } else { :conditions => { :category_id => cat } } end } end
Allows you to call something like this:
categories = user_is_admin ? :all : @current_category Article.category(categories)
Mostly useful when chaining named_scopes together. Avoids more complicated if statements.


