Notes posted to Ruby on Rails
RSS feedEdge case
NilClass#try doesn’t check for methods on itself:
nil.blank? #=> true nil.try :blank? #=> nil
touch in rails
touch is used to update the updated_at column you can create a model instance and update the updated_at value on it
Let say we have one user model
user = User.first
next you can write
user.touch
so it will run the query for you
UPDATE `users` SET `updated_at` = ‘current_date_time’ WHERE `users`.`id` = 1
Alternatively, to update some other column with the current date and time use:
model.touch(:column_name)
without a bang
We can use hash#slice if we want an Hash#extract (without bang) like behavior.
expires_in option
@concept47 do you really need to check the fragment in the controller?
ActiveRecord will execute the query when its used
cars = Car.where(:colour => 'black') # No Query cars.each {|c| puts c.name } # Fires "select * from cars where ..."
“Lazy Loading” - http://m.onkey.org/active-record-query-interface
everything is ok
Olefine, I’m not sure here is a good place for such questions (better use stackoverflow for example), but answer for your question is that Rails provide slice (and many other methods) not only for Hash class but for HashWithIndifferentAccess too such as for any other superclass of Hash, so they use
hash = self.class.new
for a reason. {} is a literal only for Hash.
for finding content
it will use all the field related to particular table so you can find data by any table field like Table name => ABC(:id, :name, :address) if you want to find data related to id or name or address than only write
ABC.find_by_id(1)
ABC.find_by_name(“abc”)
ABC.find_by_address(“abc”)
find_by_field_name will find only first data match with it
if u want to find all data than enter
ABC.find_all_by_id(1)
ABC.find_all_by_name(“abc”)
ABC.find_all_by_name(“abc”)
expires_in option
You can actually pass in an expires_in option that sets how long Rails should show the fragment before deleting it so as an example …
<% cache('homepage_sidebar', :expires_in => 10.minutes) do %> <div> ... </div> <% end %>
This only used to work with memcached but it now works with other types of Rails stores, MemoryStore, FileStore (had to use a plugin to get this behavior before) etc etc
So in your controller. You’d just do …
@posts = Posts.all if fragment_exists?('homepage_sidebar')
to avoid performing a pointless SQL query.
Not Supported on Memcached.
Just an FYI, this is not supported on Memcached, so I would avoid it if you’re using FileStore and are planning on moving over to Memcached eventually.
Ajax calls no longer whitelisted
As of Rails 3.0.4 and 2.3.11, Ajax calls are no longer whitelisted.
See: http://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails/
Use strings as parameters, not booleans
I just stumbled across this somewhere in our codebase. The first example is faulty, the second one is correct.
= f.check_box :public, {}, true, false # <input id="event_public" name="event[public]" type="checkbox" value="true" />
and:
= f.check_box :public, {}, "true", "false" # <input name="event[public]" type="hidden" value="false" /> # <input id="event_public" name="event[public]" type="checkbox" value="true" />
Nested i18n attributes
If you want to use nested attributes in a i18n file (like person :has_many => :addresses), write:
en: activerecord: attributes: person: name: "person/addresses": street: "Street name" "person/phones": area: "Area code" number: Number
Difference between fullpath
From what I’ve seen, it looks like the difference between this and #fullpath is that this method doesn’t include parameters that weren’t in the original url (i.e. parameters that were sent via POST instead of GET).
isolate_namespace description with example
Normally when you create controllers, helpers and models inside an engine, they are treated as if they were created inside the application itself. This means that all helpers and named routes from the application will be available to your engine’s controllers as well.
However, sometimes you want to isolate your engine from the application, especially if your engine has its own router. To do that, you simply need to call isolate_namespace. This method requires you to pass a module where all your controllers, helpers and models should be nested to:
module MyEngine class Engine < Rails::Engine isolate_namespace MyEngine end
end
With such an engine, everything that is inside the MyEngine module will be isolated from the application.
Detail reference: http://edgeapi.rubyonrails.org/classes/Rails/Engine.html
Accept header ignored
Rails ignores the accept header when it contains “,/” or “/,” and returns HTML (or JS if it’s a xhr request).
This is by design to always return HTML when being accessed from a browser.
This doesn’t follow the mime type negotiation specification but it was the only way to circumvent old browsers with bugged accept header. They had he accept header with the first mime type as image/png or text/xml.
Using fields_for with collection (no association)
accepts_nested_attributes_for has some detractors: http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models
But fields_for is defined both on FormBuilder and FormHelper and is still useful even when accepts_nested_attributes_for is not being used. Consider a “to do list” application where we wish to edit and update a list of tasks (Task model). I like to use a TaskCollectionController to manage the actions on the collection, it feels more RESTful than overloading a TaskController:
class TaskCollectionController < ApplicationController # task_collection_edit GET /task_collection/edit def edit @tasks = Task.all end # task_collection_update PUT /task_collection/update def update # it would be better to use a TaskCollection form object here # to make this controller skinny, # for the sake of brevity I skipped the form object params[:tasks].values.each do |attrs| if attrs[:_destroy] == '1' Task.find(attrs[:id]).destroy elsif attrs[:id].blank? Task.create(attrs.slice!(:id,:_destroy)) else Task.find(attrs[:id]).update_attributes(attrs.slice!(:id,:_destroy)) end end redirect_to task_collection_edit_path end end
In the edit view, I use fields_for to index added tasks, and it also will insert the id as a hidden field for existing tasks:
%h1 Edit Task Collection = form_tag task_collection_update_path, :method => :put do %table#tasks %tr %th Name %th Priority - @tasks.each do |task| = fields_for 'tasks[]', task, :hidden_field_id => true do |task_form| = render :partial => 'task_form', :locals => {:task_form => task_form} = button_tag 'Save' = button_tag "Add task", :type => :button, :id => :add_task %script{:type => 'html/template', :id => 'task_form_template'} = fields_for 'tasks[]', Task.new, :index => 'NEW_RECORD', :hidden_field_id => true do |task_form| render(:partial => 'task_form', :locals => {:task_form => task_form}); end :javascript $(function(){ task_form = function(){ return $('#task_form_template').text().replace(/NEW_RECORD/g, new Date().getTime())} var add_task = function(){ $('#tasks').append(task_form()) } $('#add_task').on('click', add_task) })
:hidden_field_id => true triggers the insertion of the id field, and a placeholder index “NEW_RECORD” is replaced by javascript when a task is added, as others have described here. When there’s no association, the index key is :index, vs. :child_index in the case of an association.
Here’s the partial used in the edit view:
%tr %td= task_form.text_field :name %td= task_form.select :priority, [1,2,3,4,5] %td= remove_item(task_form)
The remove_item helper triggers the deletion of persisted tasks:
module TaskCollectionHelper def remove_item(form_builder) if form_builder.object.new_record? # If the task is a new record, remove the div from the dom link_to_function( 'Remove', "$(this).closest('tr').remove()") else # However if it's a "real" record it has to be deleted from the database, # hide the form and mark for destruction form_builder.hidden_field(:_destroy) + link_to_function( 'Remove', "$(this).closest('tr').hide(); $(this).siblings().attr('value',1)") end end end
IS NOT NULL or !=
where.not()
# SELECT `users`.* FROM `users` WHERE (`users`.`id` != 1) AND (`users`.`name` IS NOT NULL) User.where.not(id: 1).where.not(name: nil)
Typing mismatch
This block
if size = options.delete(:size) options[:width], options[:height] = size.split("x") if size =~ %{^\d+x\d+$} end
has type mismatch
%r{^\d+x\d+$}
Must use :class, not 'class'
Note that
<%= content_tag_for(:li, @person, :class => “bar”) %>
does the right thing.
<%= content_tag_for(:li, @person, ‘class’ => “bar”) %>
will not!
Use dom_id( resource_instance ) to create the HTML id
In the notes on this page people use:
car_ids_#{c.id}
But you can use this function in stead:
dom_id(c)
Html inside Lable tag
I need this
<label> Show <select size="1" name="dyntable_length" aria-controls="dyntable"> <option value="10" selected="selected">10</option> <option value="25">25</option> <option value="50">50</option> <option value="100">100</option> </select> entries </label>
I made a helper method:
def entries_lablel() label_tag '' do concat 'Show ' concat content_tag(:select, options_for_select([10, 25, 50, 100]), {name: 'dyntable_length', size: 1} ) concat ' entries' end end
and In my html.erb file I called it
<%= entries_lablel %>
You can pass paramateres to make it more generic also You can add multiple select elements or any other element using the same
Do not mistakenly use serialize like other similar directives - attr_accessible, attr_accessor
serialize seems very similar to other directives that work on attributes such as attr_accessible. One may mistakenly assume that serialize can take a list of attributes. For eg:
class Tuk < ActiveRecord::Base attr_accessible :foo, :bar serialize :foo, :bar end
This may lead to a cryptic error. Eg.
puts !Tuk.first.foo.nil?
causes:
NoMethodError at /file:location undefined method `new' for :bar:Symbol
This is because it tries to parse the YAML string stored in foo as an instance of :bar.
Avoiding to_param method when using URL helper methods
I recently found myself in the situation where I needed to generate URLs which included the ID instead of the value returned from the model’s to_param method (since someone had overridden the to_param method). It turned out to be easier than I thought. You can simply pass an ID to the helper method and it will construct the URL correctly:
edit_admin_foobar_path(@foobar.id) # /admin/foobars/123/edit
Use @output_buffer to set the context.
You can use assert_select to test helpers, just have to set the @output_buffer before you do.
Code example
class CurrencyHelperTest < ActionView::TestCase setup do # can use helper methods here @output_buffer = currency 54.78 end test 'currency use a div' do asert_select 'div' end end
A simple usage example
See http://apidock.com/rails/String/inquiry
env = "production".inquiry env.production? # => true env.development? # => false
:include is also valid option
my_company.serializable_hash(:include => [:people])
use validates :name, :presence => true instead
validates_presence_of is a holdover from the Rails 2 days.
This is the way it is done now http://guides.rubyonrails.org/active_record_validations_callbacks.html#presence