我仍然认为自己是Rails的新手。我正在Rails应用程序中实现一个SMS功能,以提醒客户即将到来的约会。我的问题是,我的预约模式中有SMS方法,但我的客户端模型是phone属性所在的位置。如何从约会模型中调用我的手机属性。
这是我的预约模式
class Appointment < ApplicationRecord
enum status: { confirmed: 0, rescheduled: 1, cancelled: 2}
belongs_to :user
belongs_to :client
validates :start_time, presence: true
validates :end_time, presence: true
after_create :reminder
def reminder
@twilio_number = ENV['TWILIO_NUMBER']
account_sid = ENV['TWILIO_ACCOUNT_SID']
@client = Twilio::REST:Client.new account_sid, ENV['TWILIO_AUTH_TOKEN']
time_str = ((self.start_time).localtime).strftime("%I:%M%p on %b. %d, %Y")
reminder = "Hi #{client.name}. Just a reminder that you have an appointment coming up at #{time_str}."
message = @client.api.account(account_sid).messages.create(
:from => @twilio_number,
:to => client.phone_number,
:body => reminder,
)
end
我的客户模式
class Client < ApplicationRecord
has_many :appointments
has_many :users, through: :appointments
scope :clients_by, ->(user) { where(user_id: user.id) }
end
根据我当前的关联设置。在提醒变量中我不能只调用
reminder = "Hi #{client.name}.?
而
:to => client.phone_number
访问phone_number属性?
答案 0 :(得分:1)
是的,您的假设是正确的,您只需拨打client.<attribute>
。
但是,请注意可怕的SELECT N + 1问题。所以,假设您做了类似
的事情Appointment.all.each do {|a| a.reminder }
如果你有50个约会,这将导致51个数据库调用,一个调用加载所有约会,然后一堆调用逐个加载每个客户端。
要避免此问题,您可以使用includes
,eager_loads
或preload
,它们比单个查询更有效地加载相关数据。
本文http://blog.scoutapp.com/articles/2017/01/24/activerecord-includes-vs-joins-vs-preload-vs-eager_load-when-and-where详细介绍了这三种方法之间的区别。我引用了TL; DR摘录如下。
我粗略地概括了我对这些方法的处理方法,如下所示: 如果我只是过滤,请使用连接。 如果我正在访问关系,请从包含开始。 如果使用两个单独的查询包含很慢,我将使用eager_load强制执行单个查询并比较性能。
通过ActiveRecord访问关系时有许多边缘情况。希望这足以在使用连接,包含,预加载和eager_load时阻止一些更基本的性能延迟。
按照那篇文章的建议,我们将我的例子重写为
Appointment.all.includes(:client).each do {|a| a.reminder }