Allow to use Proc on :order option of associations

Take a look (not my production code but reproduces the desired behavior):


class Post < ActiveRecord::Base

attr_accessible :published_at, :name

has_and_belongs_to_many :categories, :order => lambda { [Category.arel_table[:published_at].desc, Category.arel_table[:name]] }

end


class Category < ActiveRecord::Base

attr_accessible :published_at, :name

has_and_belongs_to_many :posts, :order => lambda { [Post.arel_table[:published_at].desc, Post.arel_table[:name]] }

end


Category.first.posts

# => TypeError: Cannot visit Proc


Post.first.categories

# => TypeError: Cannot visit Proc

The problem happens when we have a cross reference between two models and need to use arel due to difference on quote of columns.

Sounds reasonable?

Reference: https://github.com/rails/rails/issues/6146

There has been discussion about putting a new syntax into Rails 4 that more closely resembles scopes. Example:

has_many :comments, -> { where(deleted: false).order(:created_at) }

This would solve the problem of eager evaluation because it's contained in a lambda.

I'll be looking into this when I get around to it.

Thanks John!

For this particular case, I don’t understand. What would be the
advantage of lazy evaluation?

Take a look at how some examples are handled in Sequel with regards

to associations:

http://sequel.rubyforge.org/rdoc/files/doc/association_basics_rdoc.html

See section Association Options

So, for that particular case, a single block would be enough without

the need for a proc. Here is an example using Sequel:

many_to_one(:comments){|ds| ds.where(deleted:

false).order(:created_at) }

Procs would be useful for some cases where you depend on some

dynamic data (taken from the Sequel documentation with a small typo
fix):

  Artist.one_to_many :songs, dataset: -> {
Song.select(:songs.*).join(Lyric, id: :lyric_id,
id => [:composer_id, :arranger_id, :vocalist_id, :lyricist_id])
}
Artist.first.songs_dataset
# SELECT songs.* FROM songs
# INNER JOIN lyrics ON
# lyrics.id = songs.lyric_id AND
# 1 IN (composer_id, arranger_id, vocalist_id, lyricist_id)
Also, I much prefer such approach as a generalized one than the AR

‘finder_sql’ option in a sense that it could be more easily cascaded
with other conditions.

Am I missing something?

Cheers,

Rodrigo.

Yep, cross-reference.

Both file needs to require the other to load :slight_smile:

Category definition needs Post defined

Post definition needs Category defined

We simply can’t load these files in this way.

Ah, I see, thanks.