Recent notes
RSS feedRake tasks for gem dependencies
You can manage installation and other tasks for these dependencies with rake tasks, for example:
rake gems:install # Installs all required gems for this application rake gems:unpack # Unpacks the specified gem into vendor/gems
To get all rake tasks about gems:
rake -T gems
Disable default date
If you want a date selector that initially doesn’t have a date selected you can pass it the option :include_blank.
date_select("project", "due_date", :include_blank => true)
%w(true false) != [true, false]
Don´t confuse the right:
validates_inclusion_of :published, :in => [true, false]
with the wrong:
validates_inclusion_of :published, :in => %w(true false)
cause:
%w(true false) == ["true", "false"]
Needs requiring 'enumerator' to work
This method needs that you
require 'enumerator'
for this method to be available.
Needs requiring 'enumerator' to work
This method needs that you
require 'enumerator'
for this method to be available.
Needs requiring 'enumerator' to work
This method needs that you
require 'enumerator'
for this method to be available.
Needs requiring 'enumerator' to work
This method needs that you
require 'enumerator'
for this method to be available.
Needs requiring 'enumerator' to work
This method needs that you
require 'enumerator'
for this method to be available.
Needs requiring 'enumerator' to work
This method needs that you
require 'enumerator'
for this method to be available.
Needs requiring 'enumerator' to work
This method needs that you
require 'enumerator'
for this method to be available.
Adds new methods to Object and Enumerable
For using this class you need
require 'enumerator'
Which also adds this methods to Object:
-
to_enum
-
enum_for
And this other methods to Enumerable:
-
each_slice
-
enum_slice
-
each_cons
-
enum_cons
-
enum_with_index
Some methods listed for this class need require 'enumerator'
The methods:
need that you put this require in your scripts:
require 'enumerator'
Include two level has many model example
class Issue < ActiveRecord::Base
has_many :journals end class Journal < ActiveRecord::Base belongs_to :issue has_many :details, :class_name => "JournalDetail", :dependent => :delete_all end class JournalDetail < ActiveRecord::Base belongs_to :journal end
<hr/>
issue = Issue.find(:first, :include => {:journals => :details} log record follow: SELECT * FROM `issues` LIMIT 1 SELECT `journals`.* FROM `journals` WHERE (`journals`.`journalized_id` IN (1) and `journals`.`journalized_type` = 'Issue' AND (dustbin <> 1)) SELECT `journal_details`.* FROM `journal_details` WHERE (`journal_details`.journal_id IN (1,2,876177898,935815637)) when execute follow code, then not build sql sentent: issue.journals issue.journals[0].details
Doesn't add an index
Typically you will want to have an index on foreign keys but this method doesn’t assume that. Outside of the create_table block you should follow this with add_index :
add_index :table_name, :goat_id # and, if polymorphic: add_index :table_name, :goat_type
Response to created_at/created_on and find(:first).map
A couple of comments on the comments:
The created_at/created_on thing clearly relates to the columns that have been defined in your model – it’s got nothing to do with Rails 2.1 (although the Rails 2 “timestamp” method adds the created_at column).
And find(:first), find(:last) return model objects, rather than arrays/result sets, which is why you can’t do a map on them – you can’t do anything that you would do on an Enumerable, unless the model object itself is Enumerable.
This is a private method
This is not a public method, but a private class method.
>> Person.included
NoMethodError: private method `included’ called for #<Class:0x233f084>
Specifying :include no longer necessarily joins the association
Before Rails 2.1, adding an :include=>[:association] in your find method caused ActiveRecord to generate SQL using a join. Since 2.1, it MAY NOT execute as a join.
The join executes a large query and returned potentially duplicate records for a one-to-many association. After 2.1, the query is broken down and eager-loaded using an additional query per association, passing the set of id’s to load, and avoiding the duplicate rows.
The new method eliminates duplicates, but can incur more database overhead. If you are loading a very large set of records (more than a “page”), you may need to “force” the join or use find_by_sql instead.
When you specify a “table.column” syntax within a
:conditions=>["child.name=?", name]
or
:order=>'child.name'
then ActiveRecord will build the older, full query with the join because you are referencing columns from another table to build. This will cause the duplicate rows to reappear.
Whenever you reference a column from another table in a condition or order clause, ALWAYS use the table name to prefix the column, even if it not ambiguous among the tables involved. Otherwise the query will not be executed as a join and you will receive an SQL error referencing the “missing” column.
You can “force” a join by adding a reference to the other tables in your :conditions or :options parameters, even if the test or sort is irrelevant.
Calling 'last' on a has_many assoication where the order is specified as a symbol raises an error.
Calling ‘last’ on a has_many assoication where the order is specified as a symbol raises an error. If you use :order, the value must be a string and not a symbol. (Prior to 2.1, :order would accept a string).
There is an incomplete Lighthouse ticket for this at http://rails.lighthouseapp.com/projects/8994/tickets/341-calling-last-on-a-has_many-assoication-where-the-order-is-specified-as-a-symbol-raises-an-error#ticket-341-1
Iterate and join blocks
Following LacKac’s idea, we can write render_join (useful to render a collection with a small chunks of code, where a render :partial + :spacer_template would be overkill):
def render_join(collection, join_string, &block) output = collection.collect do |item| capture(item, &block) end.join(join_string) concat(output, block.binding) end
An example of use:
<% render_join(@items, '<br />') do |item| %> <p>Item title: <%= item.title %></p> <% end %>
Current Database Name
The MySQL database adapter extends this and allows you to call
ActiveRecord::Base.connection.current_database
to get the current databases name. Useful when you are actively changing the database you are connected to and sometimes need to check the current one.
http://apidock.com/rails/ActiveRecord/ConnectionAdapters/MysqlAdapter/current_database
Current Database Name
The MySQL database adapter extends this and allows you to call
ActiveRecord::Base.connection.current_database
to get the current databases name. Useful when you are actively changing the database you are connected to and sometimes need to check the current one.
http://apidock.com/rails/ActiveRecord/ConnectionAdapters/MysqlAdapter/current_database
preload_associations manually
Usually you preload associations using :include => [ ... ]. In Rails 2.1 each association is fetched with a separate query. Something like:
Post.find(:all, :include => [:tags, :user])
will produce 3 queries - each for posts, tags and users.
But sometimes you have a complex query, which uses :joins => :other_association and conditions between multiple tables, but not the ones you need to include. Then everything is mixed back in one query like in old versions of Rails.
Another case may be when it is not possible to use :include at all, for example while using find_by_sql, but you still want/need to preload associated records.
In rails 2.1 find uses preload_associations internally, when it is possible (There are no joins or conditions between tables).
So then you can preload asociations manually from within your model:
class Post < ActiveRecord::Base
has_many :tags belongs_to :user ... def self.find_complex_with_includes posts = find_by_sql(...) # or find(:all, :joins => .....) preload_associations(posts, [:tags, :user]) posts end
end
and then do
@posts = Post.find_complex_with_includes
Namespace or modules in routes
If you have grouped controllers into a module, e.g. admin then you can specify this in the routes using the namespace method:
map.namespace :admin do |admin| admin.resources :categories end
which will map the categories resource giving urls like
/admin/categories/
/admin/categories/new
It will also generate the named routes such as new_admin_category_url and admin_category_path
script/generate syntax
To add a post_id field to a comments table, run this:
script\generate migration add_post_id_to_comment post_id:integer
See that it´s not the table name(plural), but the model name(singular),<br /> and post_id:references, does not works like in create_table.
This is the generated migration:
class AddPostIdToComment < ActiveRecord::Migration def self.up add_column :comments, :post_id, :integer end def self.down remove_column :comments, :post_id end end
Last element of an array alternative
You can also access the last element of an array with -1
[ "w", "x", "y", "z" ][-1] #=> "z"
Re: Convert an Array of Arrays to a Hash using inject
If you’re sure you have a two-level array (no other arrays inside the pairs) and exactly two items in each pair, then it’s faster and shorter to use this:
array = [['A', 'a'], ['B', 'b'], ['C', 'c']] hash = Hash[*array.flatten]
For more than two-level deep arrays this will give the wrong result or even an error (for some inputs).
array = [['A', 'a'], ['B', 'b'], ['C', ['a', 'b', 'c']]] hash = Hash[*array.flatten] # => {"A"=>"a", "B"=>"b", "C"=>"a", "b"=>"c"}
But if you’re running Ruby 1.8.7 or greater you can pass an argument to Array#flatten and have it flatten only one level deep:
# on Ruby 1.8.7+ hash = Hash[*array.flatten(1)] # => {"A"=>"a", "B"=>"b", "C"=>["a", "b", "c"]}
Regexes with groups and split
When you use a Regex with capture groups, all capture groups are included in the results (interleaved with the “real” results) but they do not count for the limit argument.
Examples:
"abc.,cde.,efg.,ghi".split(/.(,)/) => ["abc", ",", "cde", ",", "efg", ",", "ghi"] "abc.,cde.,efg.,ghi".split(/(.)(,)/) => ["abc", ".", ",", "cde", ".", ",", "efg", ".", ",", "ghi"] "abc.,cde.,efg.,ghi".split(/(.(,))/) => ["abc", ".,", ",", "cde", ".,", ",", "efg", ".,", ",", "ghi"] "abc.,cde.,efg.,ghi".split(/(.(,))/, 2) => ["abc", ".,", ",", "cde.,efg.,ghi"] "abc.,cde.,efg.,ghi".split(/(.(,))/, 3) => ["abc", ".,", ",", "cde", ".,", ",", "efg.,ghi"]
Using sweepers in script/runner
If you need to use some of your sweepers in a script/runner script or some rake task you can use this snipped:
require 'action_controller/test_process' sweepers = [ProductSweeper, UserSweeper] ActiveRecord::Base.observers = sweepers ActiveRecord::Base.instantiate_observers controller = ActionController::Base.new controller.request = ActionController::TestRequest.new controller.instance_eval do @url = ActionController::UrlRewriter.new(request, {}) end sweepers.each do |sweeper| sweeper.instance.controller = controller end
Your script will fire the ActiveRecord callbacks defined in that sweepers and you can use expire_cache, expire_fragment and also the routing helpers you have defined (hash_for_user_path, hash_for_product_path, etc.).
Using observers with script/runner
If yoo need to use some observers but you don’t want then in the initialization you can do this in your script:
ActiveRecord::Base.observers = [ProductObserver, UserObserver] ActiveRecord::Base.instantiate_observers
Your observers should work during the execution of the script.
(For the sweepers the solution is a bit different, look at my Caching module note for the complete solution).