Notes posted to Ruby on Rails
RSS feedParameter extraction logic changed in Rails 2.3!
What is documented here about Rails parameter extraction always getting the first occurrence of a key is apparently incorrect (in Rails 2.3 it gets the last occurrence).
See the following email thread on [rubyonrails-core]:
http://www.mail-archive.com/rubyonrails-core@googlegroups.com/msg08719.html
I quote:
> In the docs for ActionView::Helpers::FormHelper#check_box, when > discussing why the method adds a hidden input tag _after_ the checkbox > tag, it says > > "...Rails parameters extraction always gets the first occurrence of > any given key..." > > I'm not sure this is still the case. Indeed it changed in 2.3 but unfortunately the patch didn't update the docs. We noticed this a few days ago, they are correct now in edge.
Disable STI
I had to add “self.inheritance_column” as opposed to simply “inheritance_column” to get this to work.
Code example
class MyModel < ActiveRecord::Base # disable STI self.inheritance_column = :_type_disabled end
Accessing URL helpers in Rails 3
I’ve been upgradings an app to Rails 3 and it took me a bit to find this-
If you were using
include ActionController::UrlWriter
to get the url helpers in rails 2, you should switch to
include Rails.application.routes.url_helpers
for Rails 3
From: http://snipplr.com/view/37063/to-access-url-helpers-urlfor-etc-from-rails-console-rails-3/
Adding initialization parameters for the relevant cache store
To configure caching of f.ex. a :mem_cache_store you can pass additional parameters just after the cache type symbol:
ActionController::Base.cache_store = \ :mem_cache_store, 'a.example.org:11211', 'b.example.org:11211'
all parameters after the cache type symbol will be passed on to the corresponding cache store constructor.
Passing in parameters
If you want to pass in parameters you can do it like this:
User.get(:find_by_name, headers = {:name => "bob"}) => /users/find_by_name.xml?name=bob
For nested routes…
routes.rb
resources :companies do resources :users do member do get :find_by_name end end end
In your api code…
class User < ActiveResource::Base self.site = "/companies/:company_id" def self.find_by_name(name, company_id) User.get(:find_by_name, headers = {:name => name, :company_id => company_id} end end
Then doing…
User.find_by_name("bob", 1)
Would call
companies/1/users/find_by_name.xml?name="bob"
This works in Rails 3.1 - not sure about older versions (specifically I think the routes were done differently in < 3
Throw error after rollback
If you want to throw the exception after rolling back you can do something like this:
Company.transaction do user.save company.save x = 1/0 rescue exp = $! begin raise ActiveRecord::Rollback rescue end raise exp end
Rollback
To rollback the transaction…
transaction do unless user.save && company.save raise raise ActiveRecord::Rollback end end
Or - catch anonymous exceptions, roll back and re-throw error
transaction do user.save company.save x = 1/0 rescue exp = $! begin raise ActiveRecord::Rollback rescue end raise exp end
read_attribute/write_attribute
I went back and looked at my notes from my previous project.
Yep, these methods were removed from ActiveRecord::Base in an early version, and moved into a Module called AttributeMethods, which is then included in ActiveRecord::Base.
So the methods are available in ActiveRecord::Base… but they are defined elsewhere.
APIdock could benefit from some better linkage, and possibly a better parser to get some of the more dynamically defined methods.
Missing method definitions
THAiSi, and any others wondering this as well:
I’ve done some pretty extensive digging in to the rails code, for a couple of projects, and I’ve found that there are several methods that don’t appear in APIDock. There are several reasons for this, but I’m not sure read_attribute falls under any of them. Perhaps it has something to do with read_attribute being defined and/or redefined in the foundation for rails (they actually do some stuff to mask out a ton of default behavior of ruby for these classes, and add their own level of inheritance functionality. Things like cattr_accessor - which is like attr_accessor, but for a class, rather than an object…
class Object < ActiveRecord::Base cattr_accessor some_attr end
would allow for reading and writing a value on the class, itself. i.e.
Object.some_attr = 5
In addition, several methods, regarding validations, callbacks, etc. are actually defined dynamically, based on things like the model name, using class_eval. These are not grabbed *at all* by APIdock, and this is where I spent most of my effort in reverse engineering how rails behaves.
Hope that helps.
reload next time referenced
After calling reset on an association, it will be forced to be reloaded next time it’s referenced. Useful after you manipulate an associated object/collection with SQL, and you want to make sure subsequent uses don’t get the invalid cached version. Better than reload in that it doesn’t actually reload if not needed.
New Website for RedCloth
The Link above doesnt work anymore. This one should be the new one: http://redcloth.org/
RE: Alternative hostname generation method
According to compute_asset_host as of rails 2.0.0 the %d expansion works in the same way, it’s not a random number generated on each call but the source hash mod 4.
In my brief testing in rails 2.3.9, %d doesn’t appear to work if you use a Proc, so manual generation is of use in that case.
I18n file to change an attribute's name
If you are using Active Record, use a locale file like the one below to change a model’s attribute’s human name.
en: activerecord: attributes: picture: explanation: Description
Without using the locale file:
ruby-1.9.2-p0 > Picture.human_attribute_name("explanation") => "Explanation"
Using the locale file:
ruby-1.9.2-p0 > Picture.human_attribute_name("explanation") => "Description"
complex conditions
If you need add complex conditions you can use this:
Model.where(:foo => 'bar').where(:attr => 1).update_all("author = 'David'")
Gotcha: index name must be a string, not a symbol
Using rails 2.3.8 I kept getting an exception when i tried:
add_index :widgets, [:colour, :weight], :name => :index_by_colour_weight
it’s solved by using:
add_index :widgets, [:colour, :weight], :name => 'index_by_colour_weight'
helpers using options for select
You can now add html options to select options by creating a container with items like the following:
Code Example
['display','value',:class => 'option_class']
This will produce:
Code Example
<option value="value" class="option_class">display</option>
typo
ActionController::Steaming => ActionController::Streaming
Moved to ActionDispatch::Routing::PolymorphicRoutes
In Rails 3, this has moved to ActionDispatch::Routing::PolymorphicRoutes.
Checks if attribute is equal to '1' by default
It’s easy to overlook the :accept option which dictates that the attribute shall be ‘1’, not ‘yes’, not true, but ‘1’ only for validation to pass.
For ‘1’ shall the value be, no more, no less. ‘1’ shall be the value thou shalt validate, and thy validation shall check for ‘1’. ‘2’ shalt not thou validate, neither ‘3’, nor ‘0’, excepting that thou shall then set the value to ‘1’. true is right out. Once the value ‘1’, being the value of the attribute named, then thou shall have validation and thy object shall be valid.
link to nothing if link_to_if condition is false
When the link_to_if condition is false you can get this helper to display nothing by doing something like this
<%= link_to_if(message.user, 'Poster', message.user){} %>
^ That will display nothing if message.user does not exist.
word_wrap with breaking long words
Code
def breaking_word_wrap(text, *args) options = args.extract_options! unless args.blank? options[:line_width] = args[0] || 80 end options.reverse_merge!(:line_width => 80) text = text.split(" ").collect do |word| word.length > options[:line_width] ? word.gsub(/(.{1,#{options[:line_width]}})/, "\\1 ") : word end * " " text.split("\n").collect do |line| line.length > options[:line_width] ? line.gsub(/(.{1,#{options[:line_width]}})(\s+|$)/, "\\1\n").strip : line end * "\n" end breaking_word_wrap("Once upon a supercalifragilisticexpialidocious time",15) # => Once upon a\nsupercalifragil\nisticexpialidoc\nious time
Documentation (v3.0.1)
Documentation for this module (taken from ActiveSupport 3.0.1):
# A typical module looks like this # # module M # def self.included(base) # base.send(:extend, ClassMethods) # base.send(:include, InstanceMethods) # scope :foo, :conditions => { :created_at => nil } # end # # module ClassMethods # def cm; puts 'I am a class method'; end # end # # module InstanceMethods # def im; puts 'I am an instance method'; end # end # end # # By using <tt>ActiveSupport::Concern</tt> the above module could instead be written as: # # module M # extend ActiveSupport::Concern # # included do # scope :foo, :conditions => { :created_at => nil } # end # # module ClassMethods # def cm; puts 'I am a class method'; end # end # # module InstanceMethods # def im; puts 'I am an instance method'; end # end # end
In Rails 3 you can find it here
In Rails 3 - this validation is moved to the HelperMethods
nested attribute gotcha
Just adding to what @diabolist said :
class House
has_many :doors accepts_nested_attributes_for :doors attr_accesible :address, :doors_attributes # NOTE its plural
end
How to perform :onchange ajax call using jQuery (Rails 3)
As remote_function no longer exists in Rails 3, here is some handy substitution
<%= select_tag :assignee_id, options_for_select([["A",1],["B",2]]), :onchange => "$.post('#{model_singular_path(id)}', {'_method':'put', 'model_name[model_field]':this.value} );" %>
You can obviously pass more attributes, change method etc.
correction
I think what metavida meant was
User.find(1, 3) # ActiveRecord::RecordNotFound error
not
User.find_by_id(1, 3) # this will just return user 1
RecordNotFound when any id not found
As an example of bansalakhil’s explanation.
User.find_by_id(1) #=> #<User:0x3d54a3c @attributes={"id"=>1}> User.find_by_id(2) #=> #<User:0x3d519a4 @attributes={"id"=>2}> User.find_by_id(3) #=> nil User.find_by_id(1, 2) #=> an Array with 2 User instances User.find_by_id(1, 3) #=> an ActiveRecord::RecordNotFound error
Get the primary schema's name
If you’re using PostgreSQL and you’ve changed schema, sometimes you need to know what schema you’re in.
ActiveRecord::Base.connection.schema_search_path.split(",").first