如何将属性映射到 Rails 中的对象列表?
How to map an attribute into a list of objects in Rails?
我有四个模型。 Event
、Invitation
、Profile
和 User
.
它们有如下关系:
Events
有很多Invitations
Profiles
有很多Invitations
Profiles
属于Users
- ...反过来,
Invitations
显然属于 Events
和 Profiles
我的问题是,当我以用户身份登录时,我可以在前端访问其 id
,基于此,我想查询 [=15] 的列表=] 这样我就知道用户(他们的个人资料)是否已经被邀请或者他们仍然可以请求邀请。
我对我想要的内容的伪描述如下:获取所有事件,如果事件有邀请,请检查其中一个是否属于我用户的个人资料。如果是,请向该特定事件添加一个 applied = true 字段。 Return 所有事件,无论应用是真还是假
我想这是一个很好的 where
和 join
语句链,但我想我在这里用我的 Ruby 知识碰壁了。
感谢您的指导!
您想知道某个活动是否有邀请,其中任何一个都属于给定用户的个人资料,因此在 Event
上定义一个方法,它可以准确地告诉您:
# app/models/event.rb
class Event < ApplicationRecord
def applied(user_id)
invitations.any? do |invitation|
invitation.profile.user_id == user_id
end
end
end
# app/controllers/events_controller.rb
class EventsController < ApplicationController
def index
@events = Event.all
@current_user = current_user
end
end
那么我想你想在类似这样的视图中显示列表:
# app/views/events/index.erb
<%= render @events %>
# app/views/events/_event.erb
<tr>
<td> <%= event.name %> </td>
<td> <%= event.applied(@current_user.id) %>
</tr>
现在有一些方法可以提高效率,例如预先加载,但这是基本的建议方法。这符合您的需求吗?
我会写出代码,这样设置就清楚了。
class Invitation < ApplicationRecord
belongs_to :event
belongs_to :profile
end
class Event < ApplicationRecord
has_many :invitations
end
class Profile < ApplicationRecord
has_many :invitations
belongs_to :user
end
class User < ApplicationRecord
has_many :profiles
end
如果您想了解某个活动的用户,请使用 has_many :through
通过另一个关联访问一个关联。首先,我们设置个人资料和活动,通过他们的邀请相互了解。
class Event < ApplicationRecord
has_many :invitations
has_many :profiles, through: :invitations
end
class Profile < ApplicationRecord
belongs_to :user
has_many :invitations
has_many :events, through: :invitations
end
现在我们可以设置用户通过个人资料获得邀请,通过邀请获得活动。
class User < ApplicationRecord
has_many :profiles
has_many :invitations, through: :profiles
has_many :events, through: :invitations
end
我们也为 Event 做同样的事情,通过个人资料找到它的用户。
class Event < ApplicationRecord
has_many :invitations
has_many :profiles, through: :invitations
has_many :users, through: :profiles
end
现在活动可以找到他们的用户,用户也可以找到他们的活动。
users = event.users
events = users.events
Rails 现在知道如何从事件加入用户,使您的任务和许多其他任务变得更加轻松。
您要避免的是必须将每个事件加载到内存中。您还希望避免在查询事件列表时使用 N+1 查询,然后查询每个事件是否与您的用户匹配。那会变得很慢。我们想要获取所有事件并检查它们是否已在单个查询中应用。
首先,我们将向名为 applied 的事件添加一个伪造的列属性。这让我们可以存储一些来自查询的额外信息。
class Event < ApplicationRecord
has_many :invitations
has_many :profiles, through: :invitations
has_many :users, through: :profiles
attribute :applied, :boolean
end
然后编写填充它的查询。我们可以利用刚才建立的Event -> User关系,直接和User一起加入Event。
# We can't use bind parameters in select, quoting will have to do.
user_id = ActiveRecord::Base.connection.quote(user_id)
@events = Event
# A left outer join ensures we get all events, even ones without users.
.left_outer_joins(:users)
.select(
# Grab all of event's columns plus...
"events.*",
# Populate applied.
"(users.id = #{user.id}) as applied"
)
现在您可以在单个查询中高效地遍历事件,而无需将它们全部加载到内存中。
@events.find_each { |event|
do_something if event.applied
}
画龙点睛的是将其打包为scope以便于使用。
class Event < ApplicationRecord
has_many :invitations
has_many :profiles, through: :invitations
has_many :users, through: :profiles
attribute :applied, :boolean
scope :applied_to_user, ->(user_id) {
# We can't use bind parameters in select, quoting will have to do.
user_id = ActiveRecord::Base.connection.quote(user_id)
left_outer_joins(:users)
.select(
# Grab all of event's columns plus...
"events.*",
# Populate applied.
"(users.id = #{user.id}) as applied"
)
}
end
Event.applied_to_user(user_id).find_each { |event|
...
}
我有四个模型。 Event
、Invitation
、Profile
和 User
.
它们有如下关系:
Events
有很多Invitations
Profiles
有很多Invitations
Profiles
属于Users
- ...反过来,
Invitations
显然属于Events
和Profiles
我的问题是,当我以用户身份登录时,我可以在前端访问其 id
,基于此,我想查询 [=15] 的列表=] 这样我就知道用户(他们的个人资料)是否已经被邀请或者他们仍然可以请求邀请。
我对我想要的内容的伪描述如下:获取所有事件,如果事件有邀请,请检查其中一个是否属于我用户的个人资料。如果是,请向该特定事件添加一个 applied = true 字段。 Return 所有事件,无论应用是真还是假
我想这是一个很好的 where
和 join
语句链,但我想我在这里用我的 Ruby 知识碰壁了。
感谢您的指导!
您想知道某个活动是否有邀请,其中任何一个都属于给定用户的个人资料,因此在 Event
上定义一个方法,它可以准确地告诉您:
# app/models/event.rb
class Event < ApplicationRecord
def applied(user_id)
invitations.any? do |invitation|
invitation.profile.user_id == user_id
end
end
end
# app/controllers/events_controller.rb
class EventsController < ApplicationController
def index
@events = Event.all
@current_user = current_user
end
end
那么我想你想在类似这样的视图中显示列表:
# app/views/events/index.erb
<%= render @events %>
# app/views/events/_event.erb
<tr>
<td> <%= event.name %> </td>
<td> <%= event.applied(@current_user.id) %>
</tr>
现在有一些方法可以提高效率,例如预先加载,但这是基本的建议方法。这符合您的需求吗?
我会写出代码,这样设置就清楚了。
class Invitation < ApplicationRecord
belongs_to :event
belongs_to :profile
end
class Event < ApplicationRecord
has_many :invitations
end
class Profile < ApplicationRecord
has_many :invitations
belongs_to :user
end
class User < ApplicationRecord
has_many :profiles
end
如果您想了解某个活动的用户,请使用 has_many :through
通过另一个关联访问一个关联。首先,我们设置个人资料和活动,通过他们的邀请相互了解。
class Event < ApplicationRecord
has_many :invitations
has_many :profiles, through: :invitations
end
class Profile < ApplicationRecord
belongs_to :user
has_many :invitations
has_many :events, through: :invitations
end
现在我们可以设置用户通过个人资料获得邀请,通过邀请获得活动。
class User < ApplicationRecord
has_many :profiles
has_many :invitations, through: :profiles
has_many :events, through: :invitations
end
我们也为 Event 做同样的事情,通过个人资料找到它的用户。
class Event < ApplicationRecord
has_many :invitations
has_many :profiles, through: :invitations
has_many :users, through: :profiles
end
现在活动可以找到他们的用户,用户也可以找到他们的活动。
users = event.users
events = users.events
Rails 现在知道如何从事件加入用户,使您的任务和许多其他任务变得更加轻松。
您要避免的是必须将每个事件加载到内存中。您还希望避免在查询事件列表时使用 N+1 查询,然后查询每个事件是否与您的用户匹配。那会变得很慢。我们想要获取所有事件并检查它们是否已在单个查询中应用。
首先,我们将向名为 applied 的事件添加一个伪造的列属性。这让我们可以存储一些来自查询的额外信息。
class Event < ApplicationRecord
has_many :invitations
has_many :profiles, through: :invitations
has_many :users, through: :profiles
attribute :applied, :boolean
end
然后编写填充它的查询。我们可以利用刚才建立的Event -> User关系,直接和User一起加入Event。
# We can't use bind parameters in select, quoting will have to do.
user_id = ActiveRecord::Base.connection.quote(user_id)
@events = Event
# A left outer join ensures we get all events, even ones without users.
.left_outer_joins(:users)
.select(
# Grab all of event's columns plus...
"events.*",
# Populate applied.
"(users.id = #{user.id}) as applied"
)
现在您可以在单个查询中高效地遍历事件,而无需将它们全部加载到内存中。
@events.find_each { |event|
do_something if event.applied
}
画龙点睛的是将其打包为scope以便于使用。
class Event < ApplicationRecord
has_many :invitations
has_many :profiles, through: :invitations
has_many :users, through: :profiles
attribute :applied, :boolean
scope :applied_to_user, ->(user_id) {
# We can't use bind parameters in select, quoting will have to do.
user_id = ActiveRecord::Base.connection.quote(user_id)
left_outer_joins(:users)
.select(
# Grab all of event's columns plus...
"events.*",
# Populate applied.
"(users.id = #{user.id}) as applied"
)
}
end
Event.applied_to_user(user_id).find_each { |event|
...
}