Recent notes
RSS feedOutput format
This outputs date & time in format of yyyy-MM-ddThh-mm-ssZZZ. All values are preceded with 0 if less than 10. Hours are in 0..23 range. Timezone is sticked at the end. Watch out for capital T in the middle :)
For those who is looking for lost country_select
country_select lives on as a plugin that can be acquired from here: http://github.com/rails/country_select/tree/master
:foreign_type option
I’m not sure if this has always been around but in 2.3, belongs_to takes a :foreign_type option on polymorphic associations. This behaves the same way as :foreign_key but for the type field.
Calculating on an enumerable
Inject can easily be used to sum an enumerable or to get the product of it
[100, 200, 1000].inject(0) { |sum, value| sum += value } # => 1300 [100, 200, 1000].inject(1) { |sum, value| sum *= value } # => 20000000 # You can access members and move down in the data structures, too points.inject(0) { |sum, point| sum += point.y }
In the case of the first two examples, an easier way to do it in Ruby 1.9 is to use reduce:
[100, 200, 1000].reduce :+ # => 1300 [100, 200, 1000].reduce :* # => 20000000
Look at reduce for more examples on how to use this.
Can be used on classes, too
For example:
class C protected def foo end end p C.protected_instance_methods(false)
outputs:
["foo"]
Documentation
Good docs can be found here: http://www.artweb-design.de/2008/7/18/the-ruby-on-rails-i18n-core-api
See also: http://rails-i18n.org/wiki for an extensive list of resources.
Deprecated
This method is deprecated. You should use:
I18n.translate('activerecord.errors.messages')
Whacky edge case
The above works great as long as you select the primary key of the owning assocations.
preload_associations calls a group_by on that object so if there is no primary key attributed filled out it will reduce the records to 1 object. ex: rows = foo.find(:all,:select=>“boo.id, foo.name, foo.age, count(DISTINCT foo.id)”, :group=>“foo.name,foo.age having count( DISTINCT foo.id) > 1”,:joins=>“INNER JOIN bar.foo on bar.foo_id = foo.id”)
preload_assications(rows,:bar)
rows.first.bar.name #=> sql call already made in preload rows.last.bar.name #=> just made another sql call to get bar
fix: :select=>“foo.id, boo.id, foo.name, foo.age, count(DISTINCT foo.id)”
now preload_associations will include all the ids found instead of just the 1st one.
Weird method...
Takes three params:
- a Class constant (has to be an existing class) - a "tag" param that, if set to "tag:yaml.org,2002:binary" will call unpack("m") on the third parameter, val; any other values for tag are ignored - val can be a Hash or a String; if it's a string it is wrapped in a hash {'str' => val}, other wise...
-
an instance of klass is allocated
-
an instance of string is initialized, with the val parameter, and bound to the class context
-
for each key in val (if any!), set instance variables in the instantiated class
So, what does this method do, a part from making my eyes hurt? It loads a yaml file and instantiates a class and sets the ivars found in the yaml file. Sorta.
It is probably the worst code I have ever seen in the ruby standard libs. WTF!!
:)
How I use Optimistic Locking
I have used Optimistic locking often, but usually I only need it in one or two places in the codebase, not everywhere an object is saved whose model has a lock_version column. So what I usually end up doing is using a little module I wrote called OptimisticallyLockable (awesome name right?). Here it is:
module OptimisticallyLockable def self.included(receiver) receiver.lock_optimistically = false receiver.class_eval do def self.with_optimistic_locking original_lock = self.lock_optimistically self.lock_optimistically = true begin yield ensure self.lock_optimistically = original_lock end end end end end
When included in a model that has a lock_version column it will turn off optimistic locking. Then when you want to actually use optimistic locking you can just use the with_optimistic_locking method like this:
class Blog include OptimisticallyLockable def do_something_destructive! self.class.with_optimistic_locking do # do something important here end end end
RE: Careful when building gems
I found out a way to combine using RDoc::usage when you are building a gem. By ripping out the code from the usage method you can create your own version which opens the correct file.
In my case, I skipped the file reading and just put the usage information in a string and used that directly.
Here is my code:
$usage = %Q{ = Synopsis ... = Usage ... == Options ... } # Shamefully stolen from RDoc#usage. We cannot use RDoc::usage because # RubyGems will call this from a wrapper, and #usage is hardcoded to look # at the top-level file instead of the current one. I have changed this # code to instead just parse a string. def usage_and_exit! markup = SM::SimpleMarkup.new flow_convertor = SM::ToFlow.new flow = markup.convert($usage, flow_convertor) options = RI::Options.instance formatter = options.formatter.new(options, "") formatter.display_flow(flow) exit(0) end
Look in usage_no_exit if you want to rip stuff out. It’s up to you how and if you implement this at all, but it’s a shortcut to use the RDoc code and formatting. Do also consider doing the formatting yourself by hand and just output that string instead.
Examples
see have_at_least or have
Multiline regexps
A shortcut for multiline regular expressions is
/First line.*Other line/m
(notice the trailing /m)
For example:
text = <<-END Hello world! This is a test. END text.match(/world.*test/m).nil? #=> false text.match(/world.*test/).nil? #=> true
usage example
code
class MyModel < ActiveRecord::Base def created_today? self.created_on.to_date == Date.today end end
Careful when building gems
If you are building a gem with executables and you think about using RDoc::Usage for facilitating the --help message, think again.
usage and usage_no_exit is hardcoded to look for the initial comment in the top level file being executed, which is normally fine, but when installing a gem, RubyGems will generate a wrapper executable for you, and usage will therefore look in that wrapper file for the comment instead of your own file.
The methods contain too much code to be easily monkey patched too. Hopefully, this will be fixed in a later version.
Possible gotcha
Please note that exists? doesn’t hold all the conventions of find, i.e. you can’t do:
Person.exists?(:conditions => ['name LIKE ?', "%#{query}%"]) # DOESN'T WORK!
Getting functionality from instances
If you want to get this functionality from instances of the models too, you can easily monkey patch rails to allow this. This is only semi-bad practice, AFAIK.
In config/initializers/overrides.rb:
# # Wrapper for @model.human_attribute_name -> Model.human_attribute_name # class ActiveRecord::Base def human_attribute_name(*args) self.class.human_attribute_name(*args) end end
Now, why is this bad? Because we change a core class, and that makes maintainability a little bit harder since new developers will not know about this.
The good part is that is such a small thing and as long as human_attribute_name exists in the class, this extension will work.
Example usage:
# index.html.haml %th= User.human_attribute_name('login') %th= User.human_attribute_name('email') # ... # show.html.haml %p %strong= "#{@user.human_attribute_name('login')}: " = @user.login
In this example, about nothing was gained at all, really. A better example is when you are building helpers to do stuff like displaying model attributes for you and whatnot. Examples for this would be far too huge to show off here, but basically, you avoid having to do stuff like this:
if options.include? :model model = options[:model] model = model.class unless model.is_a? Class model.human_attribute_name(field) else # ... end
and you want to keep your views clean (@user vs. @user.class)
Nothing here
You’re probably looking for I18n::Backend::Simple.
This method will still rewrite all the values of the table
Even if you update only a small boolean flag on your record, update_attribute will generate an UPDATE statement that will include all the fields of the record, including huge BLOB and TEXT columns. Take this in account.
You can't use Symbols, but you can use Regexps
You can’t use Symbol (although Symbol is accepted with render :action => :new), like:
assert_template :new # WON'T WORK!
But you can use Regexp, e.g.:
assert_template /new/ # WORKS OK
Note that the String matched with your Regexp is the full path to the template relative to the view/ directory of your app, so this will not work:
assert_template /^new$/ # WON'T WORK!
However this might:
assert_template /^employees\/new.html.haml$/
Hash conditions require explicit key and value
When condition passed as hash, the behavior is different from a finder method. Finder methods, such as:
find(:all, :user=>user)
will apply the user_id = user.id convention, provided user is an association (e.g. belongs_to :user). The exists? method will not do the same. You must specify the foreign key name and value explicitly, i.e:
exists?(:user_id=>user.id)
Getting the object in a partial
If you need to get the object for the form inside a partial, and can’t use the instance variable, use the #object method… This is particularly useful when you’re dealing with single-table inheritance subclasses (e.g. MyOtherClass inherits from MyClass) or when you are using the same partial across different controllers.
new.html.erb
<% form_for(@my_object) do %> <%= render :partial => 'form' %> <%= submit_tag 'Create' %> <% end %>
_form.html.erb
<% if f.object.class.is_a? MyClass %> <%# do something... %> <% elsif f.object.is_a? MyOtherClass %> <%# do something else... %> <% end %>
Add Rspec files to the annotations
By default the annotations search the ‘test’ folder, but not the ‘spec’ folder if you are using Rspec. To get those specs involved do this:
require 'source_annotation_extractor' class SourceAnnotationExtractor def find(dirs=%w(app lib spec)) dirs.inject({}) { |h, dir| h.update(find_in(dir)) } end end
If you have other folders you want to check, just add them to the dirs list.
Description
Similar to Ruby’s built-in attr_writer, only it creates a class attribute writer method (as opposed to an instance attribute writer method).
Description
Similar to Ruby’s built-in attr_reader, only it creates a class attribute reader method (as opposed to an instance attribute reader method).
Use collect in nested content_tags
Remember to use #collect instead of #each in nested content_tags
arr = ['a','b','c'] content_tag :div do arr.collect { |letter| content_tag(:scan, letter) end #=> <div> # <scan>a</scan> # <scan>b</scan> # <scan>c</scan> # </div>
If you used #each you would get this (which is probably a mistake):
#=> <div> # abc # </div>
two ways to disable single table inheritance
-
Don’t use the column name ‘type’
-
Or if the first is no option for you: Tell Rails to look for a not existing column like:
class MyModel < ActiveRecord::Base
# disable STI inheritance_column = :_type_disabled end
alternative (working with 2.2.X)
ActionController::Base.relative_url_root