Flowdock

Notes posted to Ruby on Rails

RSS feed
February 20, 2013
0 thanks

It also works with strings

It works with strings:

ActiveRecord::Base.connection.column_exists?('users', 'id')

Which is helpful if you need to specify the database/schema to use:

ActiveRecord::Base.connection.column_exists?('secondary.users', 'id')
February 14, 2013 - (>= v3.2.8)
1 thank

conditional rescue from does not seem working on Rails 3.2.11

Be careful, conditional rescue_from does not work in Rails 3.2.11

February 8, 2013 - (>= v2.3.8)
0 thanks

The purpose of this method

This method keeps track of whether a hidden id field needs to be created when the form builder is generating fields for a nested model. It gets set to true by #hidden_field when that method is used to create a field named ‘id’.

Here’s an example of what this can be useful for: http://railsforum.com/viewtopic.php?id=39640

February 4, 2013
0 thanks

Your scope cannot be called 'locked'

will cause intermittent problems of the type

undefined method 'locked' for #<Class:0x007fdab3025298>

Use something like ‘access_locked’ instead

February 2, 2013
0 thanks

Other Example

##

class Exam
 cattr_reader :code, :description, :points, :instance_reader => false

 @@code = "EXM"
 @@description = "Sent Exam"
 @@points = 1000
end

In this case it’s possible to use

Exam.code # => EXM
Exam.description # => Sent Exam
Exam.points # => 1000
January 29, 2013
0 thanks

Works also with Mongoid

What works for Active Record, also works for Mongoid:

de:
  mongoid:
    attributes:
      picture:
        explanation: Description
January 26, 2013 - (v3.0.0 - v3.2.8)
0 thanks

Use sqlite3, not sqlite

Note that typically if you want to connect to an SQLite database the adapter would be “sqlite3”; not “sqlite” as depicted in the documentation above. Just using the term “sqlite” might result in the error message: “database configuration specifies nonexistent sqlite adapter”

January 23, 2013 - (>= v3.0.0)
1 thank

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:

check_box_tag( name, value, checked, html_and_other_options)

For example:

select_tag( "my_tag_id", entity.id,
  class: "progress bar update_msg", disabled: disabled?
  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:

<input class="progress_bar update_msg" 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" type="checkbox" value="4"/>

In this example, by tying into the events 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_bar", 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_bar", function(){ 
    // get id of element to hide
    var progress_bar_id = '#' + this.getAttribute('data-progress-bar');
    $(progress_bar_id).hide();
  })
  .on('ajax:complete', ".update_msg", function(evt, xhr, options){ 
    // get id of element to contain message
    var update = this.getAttribute('data-update'); 
    $("#" + update).replaceWith($(xhr.responseText).attr("id", update));
    // cause responses with these classes to fade away...
    $('.notice').fadeOut(2500);
    $('.error').fadeOut(8000);
  });
January 21, 2013 - (v3.0.0 - v3.0.9)
0 thanks

for rails >= 3

template_root= is deprecated, use prepend_view_path instead

source: ActionMailer/DeprecatedApi/ClassMethods/template_root

January 18, 2013
0 thanks

Some documentation available in RailsGuides

The Rails engines getting started guide discusses the usage of isolate_namespace: http://edgeguides.rubyonrails.org/engines.html

January 8, 2013 - (v3.0.0 - v3.2.8)
0 thanks

Minor 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.

January 8, 2013
1 thank

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
January 6, 2013
0 thanks

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.

January 4, 2013 - (>= v3.0.0)
1 thank

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);
  });
December 27, 2012 - (>= v2.3.8)
0 thanks

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"]
December 14, 2012 - (>= v3.2.1)
0 thanks

Now called class_attribute in Rails 3.2.x

See github.com/novafabrica/make_exportable/pull/4

December 5, 2012 - (v3.2.8)
0 thanks

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
December 5, 2012 - (v3.2.8)
1 thank

post user authentication info to sessions create action

post_via_redirect(“sessions”, {:user=>{:email=> user.email, :password => user.password}})

November 30, 2012
0 thanks

Beware: virtual attributes are ignored

Even though validations are called, virtual attributes are ignored.

November 30, 2012 - (v3.2.3)
0 thanks

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.

November 28, 2012 - (>= v3.0.0)
0 thanks

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 
November 24, 2012 - (>= v3.1.0)
0 thanks

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

November 24, 2012 - (v3.0.5 - v3.2.8)
0 thanks

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
November 16, 2012
0 thanks

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 ?

November 6, 2012
0 thanks

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.

November 6, 2012 - (>= v3.0.0)
0 thanks

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.

November 5, 2012 - (v3.0.0 - v3.2.8)
0 thanks

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.

October 26, 2012 - (v1.2.0 - v3.2.8)
0 thanks

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
October 26, 2012
0 thanks

#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
October 24, 2012
0 thanks

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"