Notes posted to Ruby on Rails
RSS feedMinor edit of pluralize_without_count
patrickberkeley’s method works great. I corrected the grammar a bit for inflection (the singular error).
application_helper.rb
def pluralize_without_count(count, noun, text = nil) if count != 0 count == 1 ? "an #{noun}#{text}" : "#{noun.pluralize}#{text}" end end
This should work in much older versions of Rails also.
Helper Methods inside of a Controller
When needing to include a helper method inside of a controller, instead of including the ENTIRE helper module, simply use this method like so:
module ApplicationHelper def fancy_helper(str) str.titleize end end class MyController < ApplicationController def index @title = view_context.fancy_helper "dogs are awesome" end end
Changing time/date separators
@hayafirst — it is possible to remove that “:” or change it to something else. Just pass `:time_separator` option. Inspect ActionView::Helpers::DateTimeSelector#separator method for more.
Using an unobtrusive Ajax (UJS) :onchange call to the controller#action
An :onchange call can be made using the Rails 3 jquery-ujs helper in the form:
select_tag( name, option_tags, misc_html_options, html_5_data-stuff)
For example:
select_tag( "my_tag_id", get_ids(@entity), class: "progress_and_message", data: { remote: true, url: url_for( action: :my_controller_action, id: my_id) // application symbols progress_bar: "progress_bar_div_id", update: "message_div_id" } )
The jquery_ujs looks for data-remote and data-url. These can be spelled out or placed in the data hash. The url must be formed as select_tag does not call url_for, unlike some of the other related tags. Values for application symbols can also be passed through. jQuery triggers will work on the Ajax events that occur. This generates the following:
<select class="progress_and_message" data-progress-bar="progress_bar_div_id" data-remote="true" data-update="message_div_id" data-url="/my_controller/my_controller_action/my_id" id="my_tag_id" name="my_tag_id"><option value=etc...></option>
For example, tying into the events in this case the program makes visible an existing hidden progress bar while awaiting a server response, and then displays a div containing a message returned by the server and hides the progress bar. If the div contains a class= for notice or error, then they will fade out.
$(".layout") .on('ajax:beforeSend', ".progress_and_message", function(){ // get id of element to make visible var progress_bar_id = '#' + this.getAttribute('data-progress-bar'); $(progress_bar_id).show(); }) .on('ajax:complete', ".progress_and_message", function(evt, xhr, options){ // get id of element to contain message and to hide var update = this.getAttribute('data-update'); var progress_bar_id = '#' + this.getAttribute('data-progress-bar'); $("#" + update).replaceWith($(xhr.responseText).attr("id", update)); $(progress_bar_id).hide(); // cause responses with these classes to fade away... $('.notice').fadeOut(2500); $('.error').fadeOut(8000); });
Example
NOTE: you pass all the keys and values in one long list:
fruit = ActiveSupport::OrderedHash[ 'apple', 'Apple', 'banana', 'Banana', 'kiwi', 'Kiwi fruit', ] fruit.keys => ["apple", "banana", "kiwi"]
Now called class_attribute in Rails 3.2.x
See github.com/novafabrica/make_exportable/pull/4
you will be redirect to signin, when you want to create post before signin
code
def test_should_signin_first_before_add_post get "/admin/posts/new" follow_redirect! end
post user authentication info to sessions create action
post_via_redirect(“sessions”, {:user=>{:email=> user.email, :password => user.password}})
Beware: virtual attributes are ignored
Even though validations are called, virtual attributes are ignored.
Can't find documention on :find_by option
I found code that had a :find_by option on belongs_to. I’m sure it’s more or less self explanatory, but I couldn’t find it listed anywhere as an option.
My bad, belongs_to was in a controller, not a model.
String to date conversion not necessarily symmetric
Note that converting from Date to String and back again is not necessarily symmetric, because the conversion to string may result in a format that is not properly converted by `to_date`.
For one thing, `to_date` sets the century argument in _parse to false. Thus if the default date format has a two-digit year, like the :short one, the century will be dropped.
Date.today.to_s.to_date #=> Mon, 28 Nov 0012
Actually one can see from the source that it just calls utc
From utc:
Returns a Time or DateTime instance that represents the time in UTC.
Seems to have changed in 3.1.0
Use collect instead of inject/reduce
You can still use collect when you nest content_tag . Just join the collection in the end and remember to add html_safe if you don’t want your html to be escaped.
a = ['a','b','c'] content_tag(:ul, :class => 'a class') do a.collect do |item| content_tag(:li, item) end.join.html_safe end
The last existing version
It says: The last existing version, and yet when I run a rails console in a 3.0.17 and try the method, it just works. Or does it mean it was never worked on past 2.3.8 ?
Selected parameter
If you want multiple options to be selected by default you can pass an array of values as “selected” option. It should be obvious, but odradek’s and batarski’s notes can confuse somebody in this case.
attributes that have the same names as options
For reasons that are beyond my comprehension, this piece of code
class Working include ActiveModel::Validations attr_accessor :format validates :format, :presence => true, :format => { :with => /\AWorking/ } end
works (NOTE: it has an attribute that has the same name of an option), while this
class NotWorking < ActiveRecord::Base validates :format, :presence => true, :format => { :with => /\ANot Working/ } end
does not (assuming that you have a legacy db in which you can’t change the names of the columns). It throws an ArgumentError at you. However, a crude hack is to add an explicit accessor to the :format method, like this
class WorkingAgain < ActiveRecord::Base validates :format, :presence => true, :format => { :with => /\AWorking again/ } def format read_attribute(:format) end end
Any explanation is welcome.
Specifying an accept header in your tests
To specify an accept header, you need to pass it in the second hash like this:
get '/url', nil, {'HTTP_ACCEPT' => 'application/json'}
The documentation says everything is uppercased and HTTP_ is appended when necessary, but that wasn’t working for me.
is now a subclass of Hash that preserves order (or _is_ a Hash if running Ruby 1.9 or greater)
You might not realize it preserves order because it delegates inspect to its super-class, Hash, which doesn’t preserve order. But you will see that order is preserved if you iterate or use the keys or values methods:
>> names = ['Amy Irving', 'Jane Doe', 'John Doe', 'John Updike', 'Susan Anthony'] >> ordered = names.group_by { |name| name.split.first } => #<OrderedHash {"John"=>["John Doe", "John Updike"], "Amy"=>["Amy Irving"], "Susan"=>["Susan Anthony"], "Jane"=>["Jane Doe"]}> # (note that the inspect above is in undefined order) >> ordered.keys # will be ordered properly => ["Amy", "Jane", "John", "Susan"] >> ordered.each { |first, full| puts first; full.each { |name| puts " #{name}" } } # will be ordered properly Amy Amy Irving Jane Jane Doe John John Doe John Updike Susan Susan Anthony
#performed? is an option when getting ActionController::DoubleRenderError
You can avoid `ActionController::DoubleRenderError (Can only render or redirect once per action)` with `#performed?`
For example
def index redirect_to not_found_path unless authenticated? render :action => 'update' unless performed? end
If you happen to face some weird rounding issue...
i.e.
helper.number_to_currency(187) => "190 kr"
check out your… translations! Especially ‘significant’ key… In my case it was
number: currency: format: significant: 'false'
that broke rounding. It should have been
number: currency: format: significant: ! 'false'
And now it works perfectly
helper.number_to_currency(187) => "187 kr"
To add an ID to the form
Found this the hard way, but to add an ID to the form generated by form_tag, you must explicitly make hashes.
Add ID
<%= form_tag({:action => 'create'}, {:id => 'anID'}) %>
Showing the select with a value previously known
Enter the value in the ‘value to check if exist in the list’ section and the drop down should have that selected
Code example
select_tag "name", options_for_select(list.collect{ [ text, value] }, 'value to check if exist in the list', {:include_blank => true}
Send with filename
The Content-Disposition response header holds the suggested attachment filename (i.e. “attachment; filename=fname.ext”)
Set the :disposition option to pass this name.
Controller
http = Net::HTTP.new(@page.host) res = http.post(path, info.to_query, headers) send_data res, :content_type => res.content_type, :disposition => res["Content-Disposition"], status: res.code
Clarification with use of update_all
I would like to point out that if you are on rails 2.3.11 or lower you will not be able to run ledermann code.
Ledermann Code
user.messages.update_all(:read => true)
If you are running 2.3 or later it you will have to use James code
James Code
Message.update_all({:read => true}, {:id => user.messages})
thanks guys for all the code help
Don't mix attr_accessible and attr_protected within single class.
Don’t use constructs like this one, they won’t work:
class User < ActiveRecord::Base attr_accessible :name attr_protected :id, :password_digest, :created_at, :updated_at, as: :admin end
Instead, use the same method for all roles:
class User < ActiveRecord::Base attr_accessible :name attr_accessible :name, :login, as: :admin end
—
You may want to add following to your `/config/initializers`:
class ActiveRecord::Base class << self alias :original_inherited :inherited def inherited subclass original_inherited subclass subclass.attr_accessible subclass.attr_accessible(subclass.attribute_names.map(&:to_sym) - [:id, :created_at, :updated_at], as: :admin) end end end
Don't allow mass assignments on model
Replying to elfo’s comment, you can achieve it easier, just add following line to `/config/application.rb`.
config.active_record.whitelist_attributes = true
All attributes in all models will be mass assignment protected by default. You can still use attr_accessible or attr_protected to override it.
Return value:
The result of this method is a hash of the following form:
{"table_field"=>"table value", "another_field" => 15, ...}
For example:
{"user_id"=>21}
Custom serialization
It is possible to supply a class with own (de)serialization logic to the serialize call. Given object must respond to load and dump calls.
Following example serializes symbols into their string representation and store them in database as raw strings instead of their YAML representation, i.e. :pumpkin would be stored as ‘pumpkin’, and not as ‘--- :pumpkin\n’
Example
clas SomeModel < ActiveRecord::Base class SymbolWrapper def self.load(string) string.to_sym end def self.dump(symbol) symbol.to_s end end serialize :value, SymbolWrapper end


