Active Record with Delegate and conditions
No, you can't, but you can pass the :allow_nil => true
option to return nil if the master is nil.
class User < ActiveRecord::Base
delegate :company, :to => :master, :allow_nil => true
# ...
end
user.master = nil
user.company
# => nil
user.master = <#User ...>
user.company
# => ...
Otherwise, you need to write your own custom method instead using the delegate macro for more complex options.
class User < ActiveRecord::Base
# ...
def company
master.company if has_master?
end
end
How to conditionally delegate Active Records in Ruby
Yes.
in addition to other objects, functions can be delegated to other functions.
Ex:
class Item
has_one :thing
has_one :other_thing
delegate :foo,
:bar
to: :correct_thing
def correct_thing
[conditional] ? thing : other_thing
end
end
delegate in rails active record
All those methods are a part of an ActiveRecord::Relation
. YourModel.all
returns a YourModel::ActiveRecord_Relation
(which is an ActiveRecord::Relation despite the different name). So, that delegation works a shorthand to do YourModel.all.find
without writing .all
all the time.
Rails: Calling or delegate instance method from another model
do it in a callback function...
inside your model:
after_save :update_order_status
def update_order_status
if # relevant condition
# do stuff
end
end
you're calling a class method but defining it as an instance method. in order to call:
Reservation.update_status
update_status needs to be defined as:
def self.update_status
but when you're calling a class method...you're not going to have access to self, so you won't be able to say
self.status_id # or whatever it was
that is, you won't be able to call this:
Reservation.update_status_completed # calling as class method
in one model and do this in another:
self.reservation_status_id = 5 # inside that class method trying to use instance
because you don't have an instance there to get the status_id from. To fix this, pass the value through an argument to the class method so you're not trying to rely on an object you don't have access to.
EDIT:
Can't tell exactly which reservation you're trying to update but to update all of them:
# order.rb
def update_reservations_status
if self.order_status_id == 2
self.reservations.each do |reservation|
reservation.update_status_completed
end
end
end
# reservation.rb
def update_status_completed
self.reservation_status_id = 5
self.save
end
Now the self in update status completed is referring to an instance...bc we're calling last in update_reservations_status.
Active Record Query for subset conditions
To get ClinicianProfiles that match at least one insurance:
@profiles = ClinicianProfile.joins(:insurances)
.where(insurances: { id: @patient.insurances })
.group('clinician_profiles.id')
.having("count(*) = 1")
You can then fetch the users by joining clinician_profiles:
@users = User.joins(:clinician_profile)
.where(
market: @user.university.market,
clinician_profile: { id: @profiles }
)
Rails - Delegate method to last record in has_many relation
I think you can do that if you create a method to return the last 'bs' object:
def last_bs
self.bs.last
end
then delegate:
delegate :my_method, to: :last_bs
UPDATE: This can also be achieved by:
delegate :my_method, to: "bs.last", allow_nil: true
Delegating method to has_many association ignores preloading
Explanation
The reason why all_have_title?
delegation doesn't work properly in your example is that your are delegating the method to blogs
association, but yet defining it as a Blog
class method, which are different entities and thus receivers.
At this point everybody following would be asking a question why there is no NoMethodError
exception raised when calling user.all_have_title?
in the second example provided by OP. The reason behind this is elaborated in the ActiveRecord::Associations::CollectionProxy
documentation (which is the resulting object class of the user.blogs
call), which rephrasing due to our example namings states:
that the association proxy in
user.blogs
has the object inuser
as@owner
, the collection of hisblogs
as@target
, and the@reflection
object represents a:has_many
macro.
This class delegates unknown methods to@target
viamethod_missing
.
So the order of things that are happening is as follows:
delegate
definesall_have_title?
instance method inhas_many
scope inUser
model on initialization;- when called on
user
all_have_title?
method is delegated to thehas_many
association; - as there is no such method defined there it is delegated to
Blog
classall_have_title?
method viamethod_missing
; all
method is called onBlog
withcurrent_scope
which holdsuser_id
condition (scoped_attributes
at this point is holding{"user_id"=>1}
value), so there is no information about preloading, because basically what is happening is:Blog.where(user_id: 1)
for each
user
separately, which is the key difference in comparison with the preloading that was performed before, which queries associated records by multiple values usingin
, but the one performed here queries a single record with=
(this is the reason why the query itself is not even cached between these two calls).
Solution
To both encapsulate the method explicitly and mark it as a relation-based (between User
and Blog
) you should define and describe it's logic in the has_many
association scope:
class User
delegate :all_have_title?, to: :blogs, prefix: false, allow_nil: false
has_many :blogs do
def all_have_title?
all? { |blog| blog.title.present? }
end
end
end
Thus the calling you do should result in the following 2 queries only:
user = User.includes(:blogs).first
=> #<User:0x00007f9ace1067e0
User Load (0.8ms) SELECT `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1
Blog Load (1.4ms) SELECT `blogs`.* FROM `blogs` WHERE `blogs`.`user_id` IN (1)
user.all_have_title?
=> true
this way User
doesn't implicitly operate with Blog
's attributes and you don't lose you preloaded data. If you don't want association methods operating with title
attribute directly (block in the all
method ), you can define an instance method in Blog
model and define all the logic there:
class Blog
def has_title?
title.present?
end
end
Rails delegate method with more than one association
As a personal opinion, @user.blog_hash_tag_tag_name
is horrible to look at.
That said, wanting to define both delegates at the user level is also a violation of LoD because you are using knowledge of the inner workings of blog (the fact that it belongs to a hash_tag) from the user class.
If you want to use delegates, you should add to class User
delegate :hash_tag_tag_name, to: :blog, prefix: true, allow_nil: true
and to class Blog
delegate :tag_name, to: :hash_tag, prefix: true, allow_nil: true
Building Active Record Conditions in an array - private method 'scan' called error
Try this:
Rails 2.3
class Site < ActiveRecord::Base
def self.build_conditions(ids, name=nil, state=nil)
cond = []
cond << send(:sanitize_sql_array, ["id NOT IN (?)", ids]) unless ids.empty?
cond << send(:sanitize_sql_array, ["name = ? ", name]) unless name
cond << send(:sanitize_sql_array, ["state = ? ", state]) unless state
cond.join(" and ")
end
end
Now somewhere in your controller:
Site.all(:conditions => Site.build_conditions([1,2]))
Site.all(:conditions => Site.build_conditions(nil, "ABC"))
Rails 3
class Site < ActiveRecord::Base
def self.exclude_ids_by_name_and_state(ids, name=nil, state=nil)
result = scoped
result = result.where("id NOT IN (?)", ids) if ids.present?
result = result.where(:name => name) if name.present?
result = result.where(:state => state) if state.present?
result
end
end
Now somewhere in your controller:
Site.exclude_ids_by_name_and_state([1,2])).all
Site.exclude_ids_by_name_and_state(nil, "ABC").all
Related Topics
When and Where Do I Require Files in a Rails Application
Devise Nomethoderror 'For' Parametersanitizer
Ruby: Remove Whitespace Chars at the Beginning of a String
Carrierwave How to Get the File Extension
I18N: Error Message Localization for Particular Model
How to Set the Rails Environment for My Somewhat Stand Alone Ruby Script
Advice on Using Modules with Ruby on Rails
Bash: /Home/Xxx/.Rvm/Scripts/Rvm: No Such File or Directory
Rails Scaffolding Pluralisation Is Incorrect for "Cafe"
How to Timeout Flash Messages in Rails
Get Time Object at Start of Day in a Particular Time Zone
Paperclip: Upload from Url with Extension