Notes posted to Ruby on Rails
RSS feedAssets 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.
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)
Remember, named_scope returns an array
named_scope always returns a named_scope object, that acts like an array, even if you’re using it to only find one record. So if you’re trying to perform an association on the results of a named_scope, use the first method to return the model object and not the named_scope object.
Ie:
user = User.my_name_scope user.articles # assuming User has_many Articles
will return an error. use this instead:
user = User.my_named_scope.first user.articles
(Of course this is a poor example because what you should be doing is performing the named_scope on Article with user as the condition, instead of on User. But if you do need to use the results of a named_scope to perform an association call, you have to do it this way to avoid an error.)
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)
Broadened Flash helper
Building on the below excellent example, you can create something with default options for how long it’s displayed and how long the fade is, and highlight:
def show_flash(options={}) options = {:fade => 3, :display => 3, :highlight => true}.merge(options) html = content_tag(:div, flash.collect{ |key,msg| content_tag(:div, msg, :class => key, :attributes => "style = display: none;") }, :id => 'flash-message') html << content_tag(:script, "new Effect.Highlight('flash-message');") if options[:highlight] html << content_tag(:script, "$('flash-message').appear();") html << content_tag(:script, "setTimeout(\"$('flash-message').fade({duration: #{options[:fade]}});\", #{options[:display]*1000});") end