Flowdock

Recent notes

RSS feed
March 27, 2013 - (>= v3.0.0)
0 thanks

When dealing with has_many through

The non-repeating primary key id must be used with find_in_batches.

  • User has many things

  • User has many socks through things

  • Sock has many things

  • Sock has many users through things

For the sake of argument, assume the first user has two socks and all other users have one sock. There are 1000 users in total and 1001 socks in total.

User.joins(:socks).count
=> 1001
agg = []
# Incorrect
User.joins(:socks).find_in_batches{|g| agg += g}
agg.count
=> 1000

Sock.joins(:users).count
=> 1001
agg = []
# Correct
Sock.joins(:users).find_in_batches{|g| agg += g}
agg.count
=> 1001
March 27, 2013 - (v3.0.0 - v3.2.13)
0 thanks
March 18, 2013
3 thanks

Beware - May cause performance issues

A serialized attribute will always be updated during save, even if it was not changed. (A rails 3 commit explains why: http://github.com/rails/rails/issues/8328#issuecomment-10756812)

Guard save calls with a changed? check to prevent issues.

class Product < ActiveRecord::Base
  serialize :product_data
end

bad

product = Product.first
product.save

good

product = Product.first
product.save if product.changed?
March 13, 2013
1 thank

Another Hash#without

Mange made me think, and I wanted to expand on his example with a small change.

class Hash
  def without(*keys)
    dup.without!(*keys)
  end

  def without!(*keys)
    reject! { |key| keys.include?(key) }
  end
end

h = { :a => 1, :b => 2, :c => 3 }
h.without(:a)      #=> { :b => 2, :c => 3 }
h #=> { :a => 1, :b => 2, :c => 3 }  

h.without(:a, :c)  #=> { :b => 2 }

h.without!(:a, :c) # { :b => 2 }
h #=> { :b => 2 }
March 5, 2013
0 thanks

Minor correction to Rubybull's examples?

Was your first example intended to be:

a=[11,22,31,224,44]
=> [11, 22, 31, 224, 44]
a.each.with_index { |val,index| puts "index: #{index} for #{val}" }
March 5, 2013 - (v3.0.0 - v3.2.8)
0 thanks

Exceptions raised within are ignored.

From http://guides.rubyonrails.org/active_record_validations_callbacks.html

The after_commit and after_rollback callbacks are guaranteed to be called for all models created, updated, or destroyed within a transaction block. If any exceptions are raised within one of these callbacks, they will be ignored so that they don’t interfere with the other callbacks. As such, if your callback code could raise an exception, you’ll need to rescue it and handle it appropriately within the callback.

March 1, 2013
0 thanks

Default field order

If you want to set an app wide default order for the fields (rather than passing :order each time), use the locale file.

eg. edit config/locale/en.yml to include:

en:
  date:
    order: 
      - :day
      - :month
      - :year
February 25, 2013 - (v1_9_3_125)
0 thanks

Using the undef/replace param overwrites the fallback parameter

If you want to provide a fallback Hash / Proc / Object you must not define the :undef and/or replace params since they overwrite the fallback.

How fallback works

fallback = Hash.new { '?' }
fallback["\u2014"] = "-"
"\u2014".encode!("ISO-8859-15", fallback: fallback)
=> "-"

Undef overwrites fallback:

fallback = Hash.new { '?' }
fallback["\u2014"] = "-"
"\u2014".encode!("ISO-8859-15", fallback: fallback, undef: :replace, replace: '?' )
=> "?"
February 25, 2013
0 thanks

Where did this go?

For Ruby 1.9 and later, use Kernel#Array to get this functionality.

February 23, 2013
0 thanks

Modes listed in IO class

See class IO for file open modes

February 22, 2013
0 thanks

Checking content_for

There’s a much simpler way to check if content exists or not, and it’s been provided as example in docs since 05.2010:

module StorageHelper
  def stored_content
    content_for(:storage) || "Your storage is empty"
  end
end

But this behavior was broken with SafeBuffer. You’ll be able to use it again when this issue (github.com/rails/rails/issues/9360) will be fixed and merged with master.

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

Freezing Time.now

You’d be much better off using the Timecop gem ( rubygems.org/gems/timecop ) than than manually writing monkey-patches to freeze Time.now etc.

It also supports time travel (i.e. changing the time, but allowing the clock to continue running).

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 &#x27;locked&#x27;

will cause intermittent problems of the type

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

Use something like ‘access_locked’ instead

February 3, 2013 - (v1_9_3_125)
0 thanks

How does enum#each_index differ from enum#with_each_index ?

Here is the working one each_with__index:

a=[11,22,31,224,44].each_with_index { |val,index| puts "index: #{index} for #{val}" if val < 30}
  index: 0 for 11
  index: 1 for 22
  => [11, 22, 31, 224, 44]

Below couldn’t produce the output, as with_index couldn’t work on the array.To make it workble, we need to first convert it to enumerator. And that can be done via the help of .to_enum, .each, or .map

a = [11,22,31,224,44].with_index { |val,index| puts "index: #{index} for #{val}" if val < 30}
=>NoMethodError: undefined method `with_index' for [11, 22, 31, 224, 44]:Array
       from (irb):2
       from C:/Ruby193/bin/irb:12:in `<main>'

Here is the working one with_index:

a = [11,22,31,224,44].each.with_index { |val,index| puts "index: #{index} for #{val}" if val < 30}
index: 0 for 11
index: 1 for 22
=> [11, 22, 31, 224, 44]
February 3, 2013 - (v1_9_3_125)
0 thanks

Difference between enum#with_object and enum#each_with_object

I found a very good post on SO - which clearly explained the difference between enum#with_object and enum#each_with_object. The link is as follows:

http://stackoverflow.com/questions/14671881/how-does-enumwith-object-differ-from-enumeach-with-object/14672305#14672305

February 2, 2013 - (v1_9_3_125)
1 thank

Enumerator#with_index has confusing documentation

Enumerator#with_index has confusing documentation, but hopefully this will make it clearer.

Code example

a=[11,22,31,224,44].to_enum
=> [11, 22, 31, 224, 44]
a.with_index { |val,index| puts "index: #{index} for #{val}" }
index: 0 for 11
index: 1 for 22
index: 2 for 31
index: 3 for 224
index: 4 for 44

a=[11,22,31,224,44].to_enum
=> #<Enumerator: [11, 22, 31, 224, 44]:each>
a.with_index(2){ |val,index| puts "index: #{index} for #{val}" if val > 30 }
index: 4 for 31
index: 5 for 224
index: 6 for 44
=> [11, 22, 31, 224, 44
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 14, 2013 - (>= v1_8_6_287)
0 thanks

Pass a block

While this example is not so obvious on first look what the block passed does, here’s a small explanation:

when the block is passed to this function, the uniqueness is checked based on a value returned by that block.

For example if it’s array of objects with “user_id” method, then this would be:

tasks.uniq{|t| t.user_id } # returns only tasks with unique user_id 
January 13, 2013
0 thanks

Note sure if doco is correct

(Note this was an issue in Ruby 1.9.2, 1.9.3 has been corrected, not sure why the generated doc is still incorrect)

Both exist? and exists? use the same underlying C function

file.c, line 5444

define_filetest_function("exist?", rb_file_exist_p, 1);
define_filetest_function("exists?", rb_file_exist_p, 1);

rb_file_exist_p does an rb_stat call, and just checks for no error.

rb_stat returns the result of a call to fstat, if the passed in value is a IO object, or stat (or your platforms equivalent). Both these return 0 on success, -1 on failure.

So both really just check that the underlying “thing” can respond to “stat” correctly. There are many things in a unix-style filesystem that have a “file” structure, not just traditional files. These functions help when you don’t care what type an entry is, just that it exists.

There doesn’t seem to be any difference in the two methods

File.directory? can test if a named file is a dir

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