Notes posted to Ruby on Rails
RSS feed
Have submit_tag send value as a nested resource
To have the submit_tag send it’s value within a nested resource for strong params use the name paramter.
submit_tag("Send", name: 'article[submit]')

Text improvement
Where it says: without loading a bunch of records should say: without loading a bunch of columns/attributes Considering that record usually is a row.

SQL Injection?
Note that the version of leente and timdorr are probably vulnerable to SQL Injection (through attribute param).
Probably you want to look into with_lock instead of handcrafting SQL.

arguments do not need to be an array
it’s a small point, but if you look at the source, the method is defined with the splat operator in the arguments:
def select (*fields)
this means that a list of arguments is automatically converted to an array. There is no typo in the description above.
It will also work to pass an array:
select([:field1, :field2])
although the select method interprets this as a single argument, and places it into an array (due to the splat operator), this is then passed to the _select(*fields) method, which immediately calls fields.flatten!
So either a list or an array may be passed, both will work.

How safe is this?
Could this be used against a user supplied fragment like in a url route ?

Rails 3.2 / 4.x with_scope replacement
If you’re looking for with_scope replacement for newer versions, see http://apidock.com/rails/ActiveRecord/Relation/scoping

Group method chain
The group_method parameter can be a string representing a method chain:
grouped_collection_select(:city, :country_id, @continents, 'countries.sort.reverse', :name, :id, :name)
If we were to modify the Country model so we can sort by name:
class Country include Comparable def <=>(other) self.name <=> other.name end end
The above example would have given us the countries sorted by name in descending sequence.

'max-stale' should be sent by client, not by server
3rd example is a trap.

Adding index with other operator classes (PostgreSQL)
To perform on search by LIKE:
SQL Query:
SELECT users.* FROM users WHERE name LIKE 'Doug%';
Explain:
# Without index Seq Scan on users (cost=0.00..82183.32 rows=98524 width=418) Filter: ((name)::text ~~ 'Doug%'::text)
Adding index with operator class ‘varchar_pattern_ops’
add_index :users, :name, order: {name: :varchar_pattern_ops} execute 'ANALYZE users;'
New Explain:
# With index Bitmap Heap Scan on users (cost=2444.46..56020.97 rows=98524 width=418) Filter: ((name)::text ~~ 'Doug%'::text) -> Bitmap Index Scan on index_users_on_name (cost=0.00..2419.83 rows=75940 width=0) Index Cond: ((name)::text ~>=~ 'Doug'::text)

Arguments for .select must be array
Model.select(:field, :other_field, :and_one_more) has a typo. It must take an array of arguments as the description states:
Model.select([:field, :other_field, :and_one_more])

Also useful without respond_with
Using the class method #respond_to allows controller-level specification of the allowed mime-types. Without #respond_with , it enables a
Completed 406 Not Acceptable
response rather than
ActionView::MissingTemplate
error when an unsupported type is requested.
See: http://www.justinweiss.com/blog/2014/11/03/respond-to-without-all-the-pain/

Bangladeshi Taka (BDT 1,200.95)
Code example
def to_bdt(amount) number_to_currency(amount, :unit => "BDT ", :separator => ".", :delimiter => ",") end

Include items affected in output
If the result returned from the block is an Integer, the output will include a message about that number of “rows” in addition to the elapsed time.
say_with_time "Some complex, custom work" do counter = 0 # ... do some stuff here that increments the counter ... counter end #=> "-- Some complex, custom work" #=> " -> 45.3725s" #=> " -> 52880 rows"

Include items affected in output
If the result returned from the block is an Integer, the output will include a message about that number of “rows” in addition to the elapsed time.
say_with_time "Some complex, custom work" do counter = 0 # ... do some stuff here that increments the counter ... counter end #=> "-- Some complex, custom work" #=> " -> 45.3725s" #=> " -> 52880 rows"

Opposite of persisted?
So I can find it when I look next time.

Opposite of #new_record?
So that next time I look I find it.

Non Layout Pages
A 404 error for the favicon will be thrown on pages where there is no layout if there isn’t a favicon in the public folder.
A situation would be when a controller method is used to render an image and the user chooses to open the image in a new tab bypassing the layout and the favicon_link_tag.

Find the First Instance in the Table. If None Exists, Create One.
Specify the data you’re looking for. If it exists in the table, the first instance will be returned. If not, then create is called.
If a block is provided, that block will be executed only if a new instance is being created. The block is NOT executed on an existing record.
Code example
MyStat.where(name: statistic_name).first_or_create do |statistic| statistic.value = calculate_percentage statistic.statistic_type = "percentage" end

Order with hash parameters only in ActiveRecord >= 4.0
If you use order with hash parameters on AR3 versions it wont work.


facing issue in create table (errno: 150)
I am trying to create table by writing the following code:
create_table :sam_server_user_audit do | t | t.column :user_id, :string, :limit => 100, :null => false t.column :user_type, :string, :limit => 20, :null => false t.column :status, :string, :limit => 20, :null => false t.column :created_at, :datetime, :null => false end
which generates:
CREATE TABLE `sam_server_user_audit` (`id` int(11) DEFAULT NULL auto_increment PRIMARY KEY, `user_id` varchar(100) NOT NULL, `user_type` varchar(20) NOT NULL, `status` varchar(20) NOT NULL, `created_at` datetime NOT NULL, FOREIGN KEY (user_id) REFERENCES users (id)) ENGINE=InnoDB CHARACTER SET `utf8`
here It is adding a foreign key user_id automatically.
How can I avoid that?

Ordering on associations
For ordering on the attribute of an associated model you have to include it:
Package.includes(:package_size).order("package_sizes.sort_order")

Preselecting options
To preselect options, pass in the selected options in the options hash:
{ :selected => [ selected_option_1, selected__option_2, ... ] }
Code example
grouped_collection_select(:city, :country_id, @continents, :countries, :name, :id, :name, { :selected => [1, 5, 6 ] } )


Only in ApplicationController
Seems like we can use helper_method only in ApplicationController. Even if we will create child controller, methods that will be created in child and listed in child’s helper_method will not be accessible from the view.
For example, we have
class SystemController < ApplicationController def important_method "I am important!" end end
and
class BookController < SystemController def index end end
And calling important_method from Book’s index view will raise an NoMethodError.

Be careful with .select
With 999 people in the table:
Person.select('person.firstname').find_in_batches do |group| group.each { |person| puts person.firstname } end
Will work properly.
But with 1001 people in the table, this will raise “Primary key not included in the custom select clause”. It’s a bit of a time bomb. If you’re writing tests for methods that use this, you won’t see a failure unless you’ve tested with more than records than the default batch size.

This method does not correctly dup arrays
Watch out because this method does not correctly dup arrays values.
The bug can be reproduced with the following code:
hash = { 'a' => [1,2,3,4] } dup = hash.deep_dup dup['a'].object_id == hash['a'].object_id # should return true
Rails 4 version does not have this issue because it is completely different implementation.

In Rails 4 it DOES return nil, even if the object you try from isn't nil
The try method does not raise a NoMethodError if you call a method that doesn’t exist on an object.
a = Article.new a.try(:author) #=> #<Author ...> nil.try(:doesnt_exist) #=> nil a.try(:doesnt_exist) #=> nil
Note:
a.try(&:doesnt_exist) #=> Raises NoMethodError

False query string parameters removed
This method is used in url_for (therefore in redirects as well).
If you pass a query string parameter to a url route that is false, before Rails 3.1, the generate method would reject it.
This causes issues on the redirected page if you are depending on the param to be have a specific value.
In Rails 3.2 they remove params.reject! {|k,v| !v.to_param} altogether.
So every single param you send is a string.

callbacks
As a note, AFAICT, this skips “validations” but does still run all callbacks still [like after_save, etc.] So if you’re looking for something that just updates see here: http://stackoverflow.com/a/7243777/32453