【问题标题】:What is wrong with my association?我的协会出了什么问题?
【发布时间】:2012-10-26 17:38:24
【问题描述】:

我希望建立一种关系,用户可以在其中创建帖子并标记该帖子。该帖子和那些标签属于该用户。

过去三天我一直在尝试调试它。我不知道为什么当我保存我的帖子时,user_id 没有填充到 Tag 模型中。我将 user_id 添加到 Tag 模型中。

我提前为过多的代码道歉。

用户 - has_many 帖子; has_many 标签

发布 - 属于_to用户; has_many 标签; has_many 标签通过标签

标签 - 有很多标签; has_many 通过标签发布帖子;属于用户

标记 - belongs_to 帖子;属于_to标签

ActiveRecord::Schema.define(:version => 20121031012555) do

  create_table "posts", :force => true do |t|
    t.integer  "user_id"
    t.string   "summary"
    t.datetime "created_at",  :null => false
    t.datetime "updated_at",  :null => false
  end

  create_table "taggings", :force => true do |t|
    t.integer  "post_id"
    t.integer  "tag_id"
    t.datetime "created_at", :null => false
    t.datetime "updated_at", :null => false
  end

  add_index "taggings", ["post_id"], :name => "index_taggings_on_post_id"
  add_index "taggings", ["tag_id"], :name => "index_taggings_on_tag_id"

  create_table "tags", :force => true do |t|
    t.string   "name"
    t.integer  "user_id"
    t.datetime "created_at", :null => false
    t.datetime "updated_at", :null => false
  end

  create_table "users", :force => true do |t|
    t.string   "username"
    t.string   "email"
    t.string   "crypted_password"
    t.string   "password_salt"
    t.string   "persistence_token"
    t.datetime "created_at",        :null => false
    t.datetime "updated_at",        :null => false
    t.string   "role"
  end

end

在帖子模型中:

def tag_ids=(tags_string)
    self.taggings.destroy_all

    tag_names = tags_string.split(",").collect{|s| s.strip.downcase}.uniq
    tag_names.each do |tag_name|
      tag = Tag.find_or_create_by_name(tag_name)
      tagging = self.taggings.new
      tagging.tag_id = tag.id
    end
end

【问题讨论】:

  • 您可以使用has_and_belongs_to_many 关系。这可以帮助您避免这种虚拟破坏。
  • 您在分配tagging.tag_id = tag.id 后没有保存taggings。而且我看不到您要保存的位置user_id
  • @ck3g 这是他为此提出的要点:gist.github.com/4025471
  • @ck3g HABTM 只是一个更简单的多对多关联。应该没问题。

标签: ruby-on-rails ruby-on-rails-3 activerecord associations model-associations


【解决方案1】:

如果我遗漏了什么,我深表歉意,但看起来您在创建标签时没有将用户 ID 传递给标签。使用 rails 3,您可以为多个属性执行 find_or_create_by,如下所示:

tag = Tag.find_or_create_by_name_and_user_id(tag_name, user_id)

另外,如果你只想构建 Tag 对象,而不是立即将其保存到 DB,你可以使用“find_or_initialize_by...”方法,如下所示:

tag = Tag.find_or_initialize_by_name_and_user(tag_name, user)

只要确保您的 Tag 模型有 attr_accessible :user_id(如果还没有)。

更新:抱歉,我刚刚重新阅读了您的问题,您说您确实将 user_id 传递给了标签模型。但是我在您提供的代码中看不到这一点;发生在哪里?

更新 #2 根据评论线程,您的参数映射不包含 user_id;当然,这是因为参数映射是根据表单输入构建的,而表单输入显然不包含用户输入。

我假设创建帖子时,它应该与当前登录的用户相关联。我还将假设您在某个地方有对当前登录用户的引用,我将其称为@current_user。

因为看起来您想在一个原子操作中创建帖子和相关标签,所以您可以做一件事,将当前用户添加到参数映射的副本中,如下所示:

post_params = params.clone.store(:user=>@current_user)
@post = Post.new(post_params)

可能有更好的方法来做到这一点,但这应该可行。请注意,您可能不需要复制参数映射;我管理员我不确定在这种情况下什么是最佳做法。

不管怎样,希望对你有帮助。

更新 3 由于 Ruby 散列是按照插入键的顺序迭代的,所以 svn 的 tag_ids 被设置在他的 user_id 到 Post 模型之前。为了解决这个问题,svn 颠倒了我之前建议的顺序,并确保 :user 键被插入在任何其他值之前。这是一种可能的解决方案(根据 svn 的 gist(https://gist.github.com/4027807) 修改):

post_params = {:user => current_user}.merge!(params[:post].clone)
@post = Post.new(post_params)

【讨论】:

  • 所以我的 tag_ids 是存储在模型中的虚拟属性。我已经尝试了 find_or_create_by_name_and_user_id 但我无法在 Post 模型(存储 tag_ids 的位置)中获取 user_id 信息。我的标签模型确实有 attr_accessible :user_id。我仍然不确定我做错了什么或如何做到这一点。
  • @svn 好吧,我没明白 tag_ids 在 Post 模型中。那么,如果 Post 模型有一个用户关联,为什么你不能使用 tag.user = self.user 之类的东西来获取用户(self 当然是当前的 Post 实例)?那有意义吗?如果我仍然遗漏了什么,再次抱歉。
  • 我也是这么想的!当我调试时,self.user 为 nil。在 Post 控制器中,当原始 @post = Post.new(params[:post]) 被实例化时,它会通过 tag_ids= 方法运行,此时 self.user 为 nil .. 我一直在阅读但我找不到是否应该是这种情况,如果不是,我可能会出错。我已经把代码放在一个要点gist.github.com/4025471
  • 您需要指定用户,@post = Post.new(:user_id => current_user.id) 或者您也可以在视图中指定(您可以从视图作为隐藏字段)
  • 对您要实现的目标感到困惑。你能详细说明“当我保存我的帖子时,user_id 不会填充到标签模型中”
【解决方案2】:

在控制器中的行之前,

@post = Post.new(params[:post])

添加下一行

@post = Post.new(:user_id => <assign your required user_id>)

这将使新的帖子对象在其实例方法中使用 user_id。
然后就可以使用了,下线成功

tag = Tag.find_or_create_by_name_and_user_id(tag_name, user_id)

希望对你有帮助:)

【讨论】:

  • 对不起,我不太明白你在说什么。在哪一行之前?
  • 在您的创建方法中,在“@post = Post.new(params[:post])”行之前,您应该添加给定的行,以指定您的帖子属于特定用户跨度>
猜你喜欢
  • 2016-02-08
  • 2013-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-29
  • 2015-03-15
  • 2017-09-12
相关资源
最近更新 更多