0

Rails ActiveRecord models can contain a lot of method calls and includes like this one I use:

class Food < ActiveRecord::Base
  translates :name
  belongs_to :group, class_name: 'FoodGroup', foreign_key: :food_group_id
  has_many :components, through: :food_components
  has_and_belongs_to_many :tags, join_table: 'tagged_foods', class_name: 'FoodTag'
  scope :dishes, ->{where is_dish: true}
  include PgSearch
  pg_search_scope :whose_name_starts_with_en, :against => :name_en,
  ...
end

So my question is - when does all that code execute? Every time model instance is created? Or just once?

I have this question because I need to pass current_user.id to pg_search_scope, and not sure how safe it is to assume that every model will have a correct user id.

Anri
  • 6,175
  • 3
  • 37
  • 61

2 Answers2

2

All that "stuff" basically adds extra methods into your model. eg

belongs_to :group, class_name: 'FoodGroup', foreign_key: :food_group_id

belongs_to is an example of a "macro" - it adds a load of methods into the model. http://techie.lucaspr.im/creating-class-macros/

You could write all those methods yourself, but putting in "belongs_to" saves you the bother.

belongs_to is executed when the class is loaded, and "mixes in" the new methods. Because they're pulled in from other modules, you can override any of them in your model definition.

All of the other examples you have are evaulated when the class is loaded, too.

As you suspect, when the class is loaded, the named scope is "fixed", so you can't pass arguments into it. However, there is a way to allow a named scope to take an argument, using a "lambda", which is basically a block of code. (for more info see When to use lambda, when to use Proc.new?)

scope :for_user, lambda {|user| {:conditions => {:user_id => user.id} } } 
Community
  • 1
  • 1
Max Williams
  • 32,435
  • 31
  • 130
  • 197
  • lambda! great, that is what i was missing, thanks. Just have to find a way to pass it to pg_scope – Anri Jul 01 '14 at 15:36
1

in addition to @Max Williams answer:
the

scope :for_user, lambda {|user| {:conditions => {:user_id => user.id})} } 

can also be written as

scope :dishes, ->(user) {where is_dish: true}

which is the form used in your initial code.

Martin M
  • 8,430
  • 2
  • 35
  • 53
  • thanks, i really need to pass user id to `pg_search_scope` not a regular one. It has a `ranked_by` option where you can specify your own ranking sql, and i have to put user specific sql in there. – Anri Jul 01 '14 at 15:41
  • thanks @Martin, i've not used the more up to date syntax before. – Max Williams Jul 01 '14 at 16:32