Flowdock

Recent notes

RSS feed
July 4, 2010
1 thank

Common use

I typically use require_dependency when developing a class or module that resides in my rails app, perhaps in the lib/ dir. A normal require statement does not reload my changes, so I use require_dependency in files that reference my newly developed class or module.

July 2, 2010
0 thanks

Takes array

Like assert_difference this method can take an array of expressions to evaluate all of them. For example:

assert_no_difference ['Publisher.count', 'User.count', 'Membership.count'] do
  post :create
end

It creates an assertion for each item in the array. So this will add three assertions to your test.

June 25, 2010
0 thanks

can return nil

I was surprised to get nil back when the right hand side (RHS) was nil. (I was expecting an exception.)

>> "abc" <=> nil
=> nil

Looking at the source I find you’ll get nil back in several cases when the RHS isn’t a string.

  • If the RHS doesn’t implement to_str.

  • If the RHS doesn’t implement <=>.

Assuming the RHS does implement to_str and <=>, the code delegates to the RHS and negates the result:

return - (rhs <=> self)
June 25, 2010 - (v1_8_6_287 - v1_8_7_72)
0 thanks

Can operate for both key and value for Hash

If you need to process both key and value of the Hash:

>> {"a" => "aa", "b" => "bb", "c" => "cc"}.collect {|k,v| [k,k+v]}
=> [["a", "aaa"], ["b", "bbb"], ["c", "ccc"]]
June 24, 2010
0 thanks

authenticity_token

<div style=“margin:0;padding:0”>

<input name="authenticity_token" type="hidden" value="f755bb0ed134b76c432144748a6d4b7a7ddf2b71" /> 

</div>

Helper generates a div element with a hidden input inside. This is a security feature of Rails called cross-site request forgery protection and form helpers generate it for every form whose action is not “get”.

June 23, 2010
2 thanks

Doesn't handle nested hashes

If you pass something like this:

http.set_form_data({:a => {:b => :c}})

it will completely mangle the value. So don’t use it.

June 23, 2010
0 thanks

Getting the client ip

From CgiRequest you can get the client ip in controller:

request.remote_ip
June 23, 2010
2 thanks

Accessing controller data

You can access controller attributes from views via the @controller variable.

It has some important attributes:

  • @controller.controller_name -> the name of the controller

  • @controller.request -> returns the ActionController::Request

    • @controller.request.method -> the request method ( get, post, put, delete )

    • @controller.request.host -> the request host ( ip address or hostname ) where your server runs

    • @controller.request.ip -> the ip where your browser runs

June 23, 2010
1 thank

how I use it

def rescue_action_in_public(exception)

case exception

when ActiveRecord::RecordNotFound, ActionController::UnknownAction, ActionController::RoutingError
  redirect_to errors_path(404), :status=>301
else
  redirect_to errors_path(500)
end

end

June 18, 2010
7 thanks

multiple attributes with the same validations

You can list multiple attributes if they share the same validations

validates :title, :body, :presence => true

sending the attributes as an array will return an error

validates [:title, :body], :presence => true
#=> ArgumentError: Attribute names must be symbols
June 18, 2010
0 thanks

Careful when updating foreign key directly

Seems when you change key directly it doesn’t update association automatically.

>> chicken = Chicken.first
>> chicken.head
=> old_head
>> chicken.head_id = new_head.id
>> chicken.head
=> old_head

Easy (stupid?) way to fix it:

class Chicken
  def head_id=(value)
    self.head = Head.find_by_id(value)
  end
end
June 17, 2010
0 thanks

writes the file to disk even if you pass a block

I was surprised to find that the local file is opened and written even if you pass the block. If you’re local working directory isn’t writeable or doesn’t have the space, you’re out of luck.

June 17, 2010
0 thanks

writes the file to disk even if you pass a block

I was surprised to find that the local file is opened and written even if you pass the block. If you’re local working directory isn’t writeable or doesn’t have the space, you’re out of luck.

June 13, 2010
0 thanks

Add requires!

Useful for methods that take options = {}

class Hash

def requires!(*params)
  params.each do |param| 
    raise ArgumentError.new("Missing required parameter: #{param}") unless self.has_key?(param) 
  end
end

end
June 13, 2010
0 thanks

keys to/from symbols

There’s probably a more effecient way to do this…

class Hash

def keys_to_strings
  res = {}
  self.keys.each do |k|
    if self[k].is_a?(Hash)
      res[k.to_s] = self[k].keys_to_strings
    else
      res[k.to_s] = self[k]
    end
  end
  return res
end

def keys_to_symbols
  res = {}
  self.keys.each do |k|
    if self[k].is_a?(Hash)
      res[k.to_sym] = self[k].keys_to_symbols
    else
      res[k.to_sym] = self[k]
    end
  end
  return res
end

end
June 13, 2010 - (>= v2.3.8)
0 thanks

Positioning the column. MySQL only

Add support for MySQL column positioning via #add_column and #change_column

add_column and change_column in the MySQL adapter now accept some additional options:

:first => true # Put the column in front of all the columns

:after => column_name # Put the column after ‘column_name’

class AddLastNameToUsers < ActiveRecord::Migration
  def self.up
    add_column :users, :last_name, :after => :first_name
  end

  def self.down
    remove_column :users, :last_name
  end
end

or

class AddIdToUsers < ActiveRecord::Migration
  def self.up
    add_column :urers, :id, :first => true
  end

  def self.down
    remove_column :users, :id
  end
end
June 7, 2010
2 thanks

No security

One important thing to remember is that this is NOT hidden in the source code and can be modified by an evil user so all input in a hidden field should be considered as untrustworthy and checked just like a visible field.

June 4, 2010
2 thanks

database exceptions will still be raised

Note that save() only returns false on validation errors (when valid? returns false). If other errors occur at the database level, like a database deadlock or trying to insert null into a column that doesn’t allow it, that will still raise an exception.

June 3, 2010
0 thanks

Testing Net:HTTP connections

You can use this excellent library to stub Net:HTTP connections in your automatic tests:

http://github.com/bblimke/webmock

May 31, 2010
4 thanks

Naming fragment cache

One of the common ways of using fragment caching is to cache content that’s shared across the site (eg. left navigation, menus, widgets etc.) that looks and works the same regardless of the name of the action or controller calling it. In such cases it’s very easy to just use named fragment caching eg.:

<% cache('left_nav') do -%>
  <%= display_left_nav -%>
<% end -%>
May 27, 2010
2 thanks

Use :path_prefix for the namespace

Resources are added after the :path_prefix. However if you use a :path_prefix on a resource, it overrides the namespace path instead of appending to it (as I think it should).

Here is what I wrote to create a versioned API access path.

map.namespace :api3, :path_prefix=>"/api/v3" do |api|
  api.resources :posts
  api.resources :comments, :path_prefix=>"/api/v3/post/:post_id"
end

This will create routes like

path: /api/v3/posts/1 
named_route: api3_post()
controller=>"api3/posts"
May 26, 2010
0 thanks

Prevent transactional fixtures for a specific test class

If you want to prevent a specific group of tests from being run inside a transaction, just define inside your test class the methods teardown_fixtures and setup_fixtures with empty bodies.

May 26, 2010
0 thanks

Prevent transactional fixtures for a specific suite

If you want to prevent a specific group of tests from being run inside a transaction, just define inside your test class the methods teardown_fixtures and setup_fixtures with empty bodies.

May 19, 2010
0 thanks

Looking for "to the power of"?

If you’re trying to calculate 2 to the power of 2, the ^ method is not what you want. Try ** instead.

2^2  #=> 0
2^8  #=> 10
2**2 #=> 4
2**8 #=> 256
May 18, 2010
2 thanks

How using Array methods

It’s not possible to use Array methods with a scope because it’s not an Array but an ActiveRecord::NamedScope::Scope :

this

Article.promotion.sum(&:price)

doesn’t run.

But you can use the to_a method to transform the ActiveRecord::NamedScope::Scope to an Array :

Article.promotion.to_a.sum(&:price)
May 17, 2010
2 thanks

Add has_keys? method to Hash class

class Hash

def has_keys?(*_keys)
  (_keys - self.keys).empty?
end

end

h = {1=>‘a’,2=>‘b’}

h.has_keys?(1,2) #-> true

h.has_keys?(1,3) #-> false

May 14, 2010
0 thanks

You must use the yielded object

A warning note (at least for v2.3.4): if you don’t use the yielded format object, you will get a cryptic error like this:

NoMethodError (You have a nil object when you didn't expect it!
The error occurred while evaluating nil.call):
 app/controllers/comments_controller.rb:11:in `create'

So make sure you use it!

May 11, 2010
1 thank

No Layout, other options

While it renders to the same rules as render, you need to specify params.

You’d think this would work:

render_to_string "users/profile", :layout => false

You need to do this instead

render_to_string(:layout => "users/profile", :layout => false)
May 6, 2010
1 thank

has_and_belongs_to_many_with_deferred_save

Be aware that has_and_belongs_to_many saves association to join table immediately after assign. It does NOT wait for my_object.save. Hence if save does not get through validations (or fail for any other reason), associated records will still be in the database.

Here is a nice workaround: http://github.com/TylerRick/has_and_belongs_to_many_with_deferred_save

May 5, 2010
0 thanks

Avoiding the "multiple values for a block parameter" warning

As pointed out below, you can also have optional parameters. But you will get something like “warning: multiple values for a block parameter (0 for 1)” if you omit them.

You can avoid those warnings by passing *args and picking the parameters yourself:

define_method :that_method do |*args|

  foo = args[0] || 'my default'
  # ...
end

Now the warning will be gone. Just make sure you fetch your parameters from *args and assign a default value (unless you want them to default to nil).