Notes posted to Ruby on Rails
RSS feedCatching and throwing -- don't!
@wiseleyb and @glosakti, neither of your suggestions are necessary, and both are bad practices.
This test:
test "transactions" do assert_raises ZeroDivisionError do User.transaction do 1/0 end end end
passes just fine on its own, with the transaction rolled back as you’d expect. No need to hack something ugly together.
logic in class/id
If you need to place some simple logic in class or like that, I think that best to make it with simple brackets:
Code example
<%= link_to ‘All actions’, switch_action_tab_path, :remote => true, :class => (‘selected’ if @tab == ‘all’) %>
unscoped.all / unscoped.count
At least in console, doing unscoped.all or unscoped.count initially returns expected results but, after you’ve added new records outside of the default_scope those two calls seem to use some cached values.
Therefore it should always be used with the block (as they sort of imply in the doc). unscoped { all } and unscoped {count }
Removed in 3.1.x
This method (and #auto_link_urls) has been removed in Rails 3.1 - other options are out there, such as Rinku, however there is a gem you can use for migration purposes etc, which is rails_autolink: http://rubygems.org/gems/rails_autolink
active_link_to helper gem
You should also have a look at github.com/twg/active_link_to if you need an ‘active’ class on your links.
Adding to the URL
If you want to use polymorphic routing for your object but you also need to specify other stuff like an anchor, you can explicitly generate the polymorphic url with extra options:
form_for @candidate, :url => polymorphic_path(@candidate, :anchor => 'signup')
Replaced by :on => :create
From rails 3,
before_validation_on_create
has been removed and replaced with:
before_validation :foo, :on => :create
Upgrading to 3.x
http://railscasts.com/episodes/202-active-record-queries-in-rails-3
Since this is deprecated, one can watch the Railcast for upgrading to 3.x
The equivalent is the ActiveRecord finder methods. http://apidock.com/rails/ActiveRecord/Fixture/find
Use Ruby instead!
E.g.
class TestClass < SomeSuperClass attr_accessor :sample_acc def initialize @sample_acc = [] super end end
If nil is not a valid value for this accessor, then you can just define reader for it.
class TestClass attr_accessor :sample_acc def sample_acc @sample_acc ||= 98 end end
Undocumented :location option
You can use undocumented :location option to override where respond_to sends if resource is valid, e.g. to redirect to products index page instead of a specific product’s page, use:
respond_with(@product, :location => products_url)
How to submit current url
For example to change some kind of param on select change…
<%= form_tag({}, {:method => :get}) do %> <%= select_tag :new_locale, options_for_select(I18n.available_locales, I18n.locale), :onchange => "this.form.submit();" %> <% end %>
How to change format automatically depending on locale...
… without passing locale option.
In your application_helper.rb (or in other helper) place following code:
def number_to_currency(number, options = {}) options[:locale] ||= I18n.locale super(number, options) end
Then, in your locale files:
en-GB: number: currency: format: format: "%n %u" unit: "USD"
And that is it :)
@Mange
If you’re actually looking to cut down on code why not use .map instead of the longer .collect?
Using a block with image_tag
HTML5 officially supports block-level elements in the anchor tag and Rails 3 allows you to pass a block to image_tag:
<%= image_tag(some_path) do %>
<%= content_tag(:p, "Your link text here")
<% end %>
Without module
If you want to have only the path prefix without namespacing your controller, pass :module => false.
Normal:
namespace :account do resources :transactions, :only => [:index] end account_transactions GET /account/transactions(.:format) {:controller=>"account/transactions", :action=>"index"}
With :module => false:
namespace :account, :module => false do resources :transactions, :only => [:index] end account_transactions GET /account/transactions(.:format) {:controller=>"transactions", :action=>"index"}
Additional Format meaning
%e - Day of the month, without leading zero (1..31)
1.9 behavior
“In Ruby 1.9 and newer mb_chars returns self’”
This would seem to be a lie. At least in rails 3.1.0 and ruby 1.9.2, mb_chars still returns a proxy object with additional useful methods defined on it that aren’t on a 1.9.2 String.
ruby-1.9.2-p180 :007 > "àáâãäå".normalize(:kd) NoMethodError: undefined method `normalize' for "àáâãäå":String ruby-1.9.2-p180 :008 > "àáâãäå".mb_chars.normalize(:kd) => àáâãäå
Parsing the Date Params into a New Date Object.
Useful for when you need to create a Date object from these manually, such as for reporting.
If the date select input is start_date and it belongs to the report form object:
@start_date = Date.civil(params[:report]["start_date(1i)"].to_i, params[:report]["start_date(2i)"].to_i, params[:report]["start_date(3i)"].to_i) @start_date.class # => Date @start_date # => Sun, 25 Sep 2011 # For example.
Use a similar method for DateTime situations.
this works, but doesn't make sense
does it?
replace(klass.find(ids).index_by { |r| r.id }.values_at(*ids))
equals
replace(klass.find(ids))
I see no point in making it that complicated
beware of trying to dup in subclass inside class context
The example of adding to an array without effecting superclass:
# Use setters to not propagate changes: Base.setting = [] Subclass.setting += [:foo]
That’s right as far as it goes. But beware when you are in context of class definition:
class Subclass < Base # possibly wrong, ruby seems to get # confused and think you mean a local # var, not the class ivar setting += [:foo] # But this will work: self.setting += [:foo] # Or: self.setting = self.setting.dup self.setting << :foo [...] end
Find a Selected Option in a Drop Down.
You can find the selected option (or options for multiple select inputs) with the following:
assert_select('select#membership_year option[selected]').first['value']
more options
useful options are:
:root => ‘object’, :skip_instruct => true, :indent => 2
:builder can also be used to pass your own Builder::XmlMarkup instance.
Some unexpected behaviour
When using Array as default value, it behaves more like cattr_accessor…
class A attr_accessor_with_default :b, [] end x = A.new x.b << 1 #puts x.b.inspect => [1] y = A.new y.b << 2 #puts y.b.inspect => [1, 2]
First example simplified
The first code example may be simplified, since the call to method to_xml is made implicitly anyway:
def index @people = Person.find :all respond_to do |format| format.html format.xml { render :xml => @people } end end
Tested w/ Rails 3 and returning true/false ignored
Per http://ar.rubyonrails.org/classes/ActiveRecord/Callbacks.html “If a before_* callback returns false, all the later callbacks and the associated action are cancelled. If an after_* callback returns false, all the later callbacks are cancelled.” [and presumably associated action is not canceled]
So, the callback chain will be broken, but the save will still happen.
Also ran into this: http://innergytech.wordpress.com/2010/03/08/dont-put-validations-in-after_save/
Passing an object as argument
It is possible to pass an instance of a record to the method. See the documentation of polymorphic_url (http://apidock.com/rails/ActionDispatch/Routing/PolymorphicRoutes).