【问题标题】:insert data through third table通过第三个表插入数据
【发布时间】:2016-04-01 11:39:21
【问题描述】:

我有 3 个没有控制器的模型(客户端、用户和管理员)

class Admin < ActiveRecord::Base
    validates_presence_of :username, :user_id, :client_id
    belongs_to :client
    belongs_to :user
end

class Client < ActiveRecord::Base
    validates_presence_of :name
    has_many :admins
    has_many :users, :through => :admins
end

class User < ActiveRecord::Base
    validates_presence_of :name, :email
    has_many :admins
    has_many :clients, :through => :admins
end

所以当我在做的时候

u = User.first.clients.new(name: 'First Client')
u.save

然后一切正常

(0.2ms)  begin transaction SQL (0.6ms)  INSERT INTO "clients" ("name",
"created_at", "updated_at") VALUES (?, ?, ?)  [["name", "First
Client"], ["created_at", "2015-12-27 10:38:47.790787"], ["updated_at",
"2015-12-27 10:38:47.790787"]]    (98.3ms)  commit transaction  =>
true

但是当我尝试查看时

2.2.2 :130 >   User.first.clients
User Load (0.5ms)  SELECT  "users".* FROM "users"  ORDER BY "users"."id" ASC LIMIT 1   Client Load (0.2ms)  SELECT "clients".* FROM "clients" INNER JOIN "admins" ON "clients"."id" = "admins"."client_id" WHERE "admins"."user_id" = ?  [["user_id", 1]] => #<ActiveRecord::Associations::CollectionProxy []>

那么如何将数据插入第三张表? 我对此进行了很多搜索,但没有解决方案,因为这里的复杂情况是第三张表Admin 也有它的必填列Username。 另外,如何通过Admin 表将数据插入UserClient 表中。

【问题讨论】:

  • 查看日志可以看到,当你保存一个新的客户端时,它只会创建Client记录,而不会创建Admin记录。而搜索查询正在查看 Admin 表并且找不到任何记录。尝试类似:c = Client.create(name: "name") 然后User.first.clients &lt;&lt; c
  • 是的,谢谢@Kkulikovskis 的回复,我已经尝试过你所说的,但问题是当我这样做时,它给了我,并且用户名的错误不能为空,这是在管理模型中和当我尝试提供用户名时,它会显示未知属性“用户名”
  • 哦,对不起。没有注意到用户名字段。那么在那种情况下,除了单独创建它们之外,我没有看到任何其他方式。例如c = Client.new(name: name); u = User.first; Admin.create(username: username, client: c, user: u)
  • nups 不工作它只是说开始事务回滚事务和 Client.first.users 仍然是#<:associations::collectionproxy>
  • 我的错。客户端对象未持久化到数据库。检查我的答案,看看它是否有效

标签: ruby ruby-on-rails-4 activerecord has-many-through


【解决方案1】:

让我一一回答你的问题

1:那么如何将数据插入到第三张表中

official document中提到的

4.3.1 has_many 添加的方法

当你声明一个 has_many 关联时,声明类 自动获取关联相关的16种方法

collection<<(object, ...)

你的情况

u = User.first.clients.new(name: 'First Client')

应该是

clients = User.first.clients
client = Client.new(name: 'First Client')
clients << client

集合


2: User.first.clients 这是如何工作的

collection(force_reload = false)

collection 方法返回一个包含所有关联的数组 对象。如果没有关联对象,则返回空 数组。

希望这能帮助你正确理解!!!

【讨论】:

    【解决方案2】:

    我知道我已经在 cmets 中说明了这一点,但它肯定会起作用:

    由于Admin 模型对username 进行了验证,因此无法简单地将client 添加到user.clients 集合中,因为这会导致ActiveRecord::Validation 错误。

    相反,您应该分别执行这些步骤,或者创建一个可以一次性完成所有步骤的方法:

    1. 创建一个用户对象:user = User.create(name: "name", email: "email@email.com")
    2. 创建一个客户端对象client = Client.create(name: "name")
    3. 创建一个管理对象admin = Admin.create(username: "username", user: user, client: client)

    这将创建必要的表条目,因此当您检查user.clients 时,它将在admins 表中查找user_id = user.id 中的所有条目,然后检索所有相应的客户端。

    如果您在控制台中执行此操作,则在完成所有步骤后重新加载您的用户实例以查看客户端: user.reload.clients

    为了让您的代码更有条理并一次完成所有这些步骤,您可以将其包装在用户实例方法中。例如:

    对于用户类

    def add_client(client_name, admin_username)
      client = Client.create(name: client_name)
      admin = Admin.create(username: admin_username, client: client, user: self)
    end
    

    【讨论】:

    • 感谢这行得通,但不是单独创建,您能否说明一种以简单的单一方式创建它的方法,因为当我为此制作控制器时,这对我来说很容易。
    • @MalwareSkiddie 很高兴为您提供帮助 :) 请善待并标记答案。
    • 我不能这样做,因为我没有足够的声誉这样做。感谢您的反馈!一旦您总共获得 15 声望,您的投票将改变公开显示的帖子分数对不起:/
    【解决方案3】:

    当您创建这样的客户端时u = User.first.clients.new(name: 'First Client')
    它只插入行和写列name, created_at, updated_at

    当你像这样打电话给User.first.clients时,
    它找到 User.first 拥有的管理员。然后由管理员找到客户。

    因此,没有与您首先创建的客户端有关系的管理员。

    你应该在创建客户端的时候设置admin_id(这个列可能存在于clients表中),像这样

    user = User.first
    client = user.clients.create(name: 'xxx')
    user.clients << client
    

    【讨论】:

    • 这并不完全正确,因为 has_many through 应该在不明确说明 admin_id 的情况下处理这一点。
    • ...clients.new(...)ActiveRecord::Associations::CollectionProxy关系数组中没有new()方法,只有build
    • @Kkulikovskis 否,activerecord 如何确定创建新客户端时选择哪些管理员 ID?用户有很多管理员,代码没有指定admin_id,你在控制台试过吗?
    • @Зелёный #new#build 都可以
    • 哦,我的错,是别名。
    猜你喜欢
    • 2018-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-15
    • 1970-01-01
    • 2019-08-02
    • 1970-01-01
    相关资源
    最近更新 更多