如果不存在新主题,如何以惯用方式创建新主题,如果主题确实存在,如何创建与会议的关联?
我正在开展一个有会议和主题的项目。它们通过ConferenceTopic对象相互关联。话题'名字是独一无二的。
以下是我在名为#find_or_create_topic_with
的会议上创建的自定义方法,该方法采用名称参数。我之所以这样做,是因为当我在会议主题上尝试#find_or_create_by
名称时,我没有成功为第二个主题创建一个名称(下面的Rails控制台日志)
The commit for this kludge is on Github.
class Conference < ActiveRecord::Base
…
def find_or_create_topic_with(name)
if topic = Topic.find_by(name: name)
self.topics.include?(topic) ? topic : self.topics << topic
else
self.topics.create(name: name)
end
end
end
关于主题的find_or_create_by的Rails控制台日志
2.1.2 :001 > Conference.last.topics.find_or_create_by(name: "fun")
Conference Load (1.0ms) SELECT "conferences".* FROM "conferences" ORDER BY "conferences"."id" DESC LIMIT 1
Topic Load (0.5ms) SELECT "topics".* FROM "topics" INNER JOIN "conference_topics" ON "topics"."id" = "conference_topics"."topic_id" WHERE "conference_topics"."conference_id" = $1 AND "topics"."name" = 'fun' LIMIT 1 [["conference_id", 3]]
(0.1ms) BEGIN
Topic Exists (0.4ms) SELECT 1 AS one FROM "topics" WHERE "topics"."name" = 'fun' LIMIT 1
SQL (0.3ms) INSERT INTO "topics" ("created_at", "name", "updated_at") VALUES ($1, $2, $3) RETURNING "id" [["created_at", "2014-08-31 18:57:56.274109"], ["name", "fun"], ["updated_at", "2014-08-31 18:57:56.274109"]]
SQL (0.5ms) INSERT INTO "conference_topics" ("conference_id", "created_at", "topic_id", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id" [["conference_id", 3], ["created_at", "2014-08-31 18:57:56.287526"], ["topic_id", 8], ["updated_at", "2014-08-31 18:57:56.287526"]]
(2.1ms) COMMIT
=> #<Topic id: 8, name: "fun", created_at: "2014-08-31 18:57:56", updated_at: "2014-08-31 18:57:56">
2.1.2 :002 > Conference.first.topics.find_or_create_by(name: "fun")
Conference Load (0.6ms) SELECT "conferences".* FROM "conferences" ORDER BY "conferences"."id" ASC LIMIT 1
Topic Load (0.4ms) SELECT "topics".* FROM "topics" INNER JOIN "conference_topics" ON "topics"."id" = "conference_topics"."topic_id" WHERE "conference_topics"."conference_id" = $1 AND "topics"."name" = 'fun' LIMIT 1 [["conference_id", 1]]
(0.2ms) BEGIN
Topic Exists (0.3ms) SELECT 1 AS one FROM "topics" WHERE "topics"."name" = 'fun' LIMIT 1
(0.2ms) COMMIT
=> #<Topic id: nil, name: "fun", created_at: nil, updated_at: nil>
2.1.2 :003 > Conference.first.topics
Conference Load (0.5ms) SELECT "conferences".* FROM "conferences" ORDER BY "conferences"."id" ASC LIMIT 1
Topic Load (0.3ms) SELECT "topics".* FROM "topics" INNER JOIN "conference_topics" ON "topics"."id" = "conference_topics"."topic_id" WHERE "conference_topics"."conference_id" = $1 [["conference_id", 1]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Topic id: 7, name: "ruby", created_at: "2014-08-31 18:40:40", updated_at: "2014-08-31 18:40:40">]>
以下是查找主题会议的日志&#34; fun&#34;
2.1.2 :015 > Topic.find_by(name: "fun").conferences
Topic Load (0.5ms) SELECT "topics".* FROM "topics" WHERE "topics"."name" = 'fun' LIMIT 1
Conference Load (0.3ms) SELECT "conferences".* FROM "conferences" INNER JOIN "conference_topics" ON "conferences"."id" = "conference_topics"."conference_id" WHERE "conference_topics"."topic_id" = $1 [["topic_id", 8]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Conference id: 3, name: "TooLongDidn'tCareConf", location: "Boston", code_of_conduct: false, childcare: false, last_years_attendance: 0, created_at: "2014-08-31 17:47:35", updated_at: "2014-08-31 17:47:35">]>
2.1.2 :016 > Topic.find_by(name: "fun").conferences.count
Topic Load (0.5ms) SELECT "topics".* FROM "topics" WHERE "topics"."name" = 'fun' LIMIT 1
(0.3ms) SELECT COUNT(*) FROM "conferences" INNER JOIN "conference_topics" ON "conferences"."id" = "conference_topics"."conference_id" WHERE "conference_topics"."topic_id" = $1 [["topic_id", 8]]
=> 1
我希望收集代理包含第一次和最后一次会议,并且计数为2.只有#find_or_create_by
我只能将它与首次创建的会议相关联,而不是后续会议找到id为nil的主题。
答案 0 :(得分:2)
只是阅读了代码,看起来你正在尝试满足三个用例:
我认为您的代码很好。真。没有什么太重要的,我会立即想要重写它。
那就是说,我可能会这样写:
def find_or_create_topic_with(name)
transaction do
topic = Topic.where(name: name).first_or_create!
self.topics.where(topic: topic).first_or_create!
end
rescue
# need to handle uniqueness violations, etc.
end
一些补充说明:
如果有任何不合理的话,请随意通过Twitter或其他任何方式来打我。
答案 1 :(得分:0)
看起来像会议has_many主题。鉴于此,您应该只能在.topics
关系上使用find_or_create_by
:
topic = my_conference.topics.find_or_create_by(name: "Name")
# topic will now contain either a newly created Topic that is associated with `my_conference`,
# or will be the existing Topic with name "Name" from `my_conference.topics`.