Notes posted by eric_programmer
RSS feedUnusual block calling
It is important to note that the block form of this method is unlike any other block form in Rails. You would expect this to work:
<%= f.label :terms_and_conditions do %> Accept <%= link_to_page 'Terms and Conditions' %> <% end %>
But doing this ends up messing up the form (I ended up with the form repeating itself). Instead you need to do:
<%= f.label :terms_and_conditions do 'Accept ' + link_to_page('Terms and Conditions') end %>
Which is really only mildly better than not using the block form:
<%= f.label :terms_and_conditions, 'Accept ' + link_to_page('Terms and Conditions') %>
You are actually better of using capture if your code lends itself to the first non-working form:
<%= f.label :terms_and_conditions, (capture do %> Accept <%= link_to_page 'Terms and Conditions' %> <% end) %>
Or if you prefer brackets to parenthesis you can do:
<%= f.label :terms_and_conditions, capture { %> Accept <%= link_to_page 'Terms and Conditions' %> <% } %>
Backport from 1.9
Below is a backport of the Ruby 1.9 implementation (minus some encoding stuff). The main thing this provides you is the ability to say :foo => [‘bar’, ‘baz’] and have that turn into foo=bar&foo=baz (i.e. multiple values for the same key).
Just require into your project and use it like you are on 1.9.
module Net module HTTPHeader def set_form_data(params, sep = '&') query = URI.encode_www_form(params) query.gsub!(/&/, sep) if sep != '&' self.body = query self.content_type = 'application/x-www-form-urlencoded' end alias form_data= set_form_data end end module URI def self.encode_www_form(enum) enum.map do |k,v| if v.nil? k elsif v.respond_to?(:to_ary) v.to_ary.map do |w| str = k.dup unless w.nil? str << '=' str << w end end.join('&') else str = k.dup str << '=' str << v end end.join('&') end end
label DOES translate
Maybe it used to not translate but I know it does as of 2.3.8. It is first lookup on the key:
helpers.label.<object_name>.<method_name>
If that doesn’t return anything it will use the human_attribute_name method on ActiveRecord::Base to translated which uses:
activerecord.attributes.<object>.<attribute>
I generally use both of these keys even when I don’t want to translate but just to have a single place where all my adjusted labels are stored.
If any form will need to use the same adjustment given the same object and attribute then I put in on the activerecord key. If the adjustment is form specific then I put it on the helpers key. Here is an example from real working code:
en: activerecord: attributes: "content/rich_text": name: Page name helpers: label: content_rich_text: testimonial_enabled: Enabled
Note that my AR object is a namespaced object (Content::RichText). In the activerecord key I need to change this to content/rich_text so if can find the correct key and put it in quotes to make it valid YAML. At the helper level on the other hand the namespace simply becomes an _.
Takes array
Like assert_difference this method can take an array of expressions to evaluate all of them. For example:
assert_no_difference ['Publisher.count', 'User.count', 'Membership.count'] do post :create end
It creates an assertion for each item in the array. So this will add three assertions to your test.
Alternate for Rails 2.0
Obviously these methods are protected so usage in an app is discouraged. But if you need to use it anyway for some reason Rails 2.0 also has sanitize_sql_for_conditions which operates exactly like sanitize_sql used to (i.e. it determines if it needs to be processed as an array or hash). So if you are going to blow by the protected status might as well use the easier version. :)
constantize
@ncancelliere - Instead use constantize which is provided as part of ActiveSupport. It is much easier. So:
mystring.constantize
Easier Universal Partials
@hosiawak provides a great example of how to use polymorphic_path to produce universal partials. You can actually simply his example even more with the following:
<%= link_to 'Edit', edit_polymorphic_path(obj) %> <%= link_to 'Delete', obj, :method => :delete %>
So the things to note are that in addition to polymorphic_path, Rails also provides an “edit_” version just like on your resources so you can use that instead of specifying the action specifically. The second thing to remember is if you pass just the raw object as the path then then rails will automatically wrap it in a call to polymorphic_path.
Alternative force initial value
@Bounga - Thanks for the suggestion. Didn’t know about that method. An alternative method I have used is just to assign the default value to the object in your controller. For example your “new” action might now look like:
def new @ecard = Ecard.new params[:ecard] @ecard.sender ||= 'contact@host.com' end
Replace allowed tags/attributes
The docs above state how to add and remove tags from the default list. But what if you just want to replace the entire list with a list of your own? You can easily do that with the following code:
ActionView::Base.sanitized_allowed_tags.replace %w(strong em b i hr br ul ol li blockquote) ActionView::Base.sanitized_allowed_attributes.replace %w(href)
Note that if you put this in your initialization block you must use the config.after_initialize hack (to override the default that will be set) but if you put it in an initializer (i.e. a file in the initializers directory) that code is executed after Rails initialization so no need to use any hack. Just use the code above.
Default allowed tags and attributes
I found it a bit hard to find the default tags and attributes in the docs.
As of Rails 2.2.2 they are:
Tags
del, dd, h3, address, big, sub, tt, a, ul, h4, cite, dfn, h5, small, kbd, code, b, ins, img, h6, sup, pre, strong, blockquote, acronym, dt, br, p, div, samp, li, ol, var, em, h1, i, abbr, h2, span, hr
Attributes
name, href, cite, class, title, src, xml:lang, height, datetime, alt, abbr, width
Getting the latest list
You can query for this list yourself with the following code on the console:
>> puts helper.sanitized_allowed_tags.to_a * ", " ... will output tag list ... >> puts helper.sanitized_allowed_attributes.to_a * ", " ... will output attribute list ...
The same principal can probably be applied to sanitize_css.
link_to_if for named routes
Back before named routes we used to say things like:
<%= link_to_if message.user, 'Poster', :controller => 'users', :action => 'show', :id => message.user %>
This would make the text “Poster” only link if message has a user. But with named routes this has become more complicated. Our first try is something like:
<%= link_to_if message.user, 'Poster', user_path(message.user) %>
Although this looks nice it causes an error since the path is generated prior to the condition not after the condition like using a hash is done. To get around this problem I have found two solutions:
-
If you are linking to the “show” path then you can just pass the object. This will force the path to not be generated until after the condition (like a hash is done). For example:
<%= link_to_if message.user, 'Poster', message.user %>
-
The previous workaround works great if you want to link to the show action. But what if you want to link to another action (say the edit action). In this case the best way I have found is to use the hash_for* helpers generated with the routing resource. So:
<%= link_to message.user, 'Poster', hash_for_edit_user_path(:id => message.user) %>
A little more awkward than the previous workaround but it is the best I can come up with. Any other suggestions (other than going back to manually typing the hash)?