【问题标题】:has_many through association does not save relationshiphas_many 通过关联不保存关系
【发布时间】:2015-12-13 08:50:24
【问题描述】:

我有两个模型通过关联加入了 has_many:

这是表格:

  create_table "organizations", force: :cascade do |t|
    t.string   "name"
    t.string   "description"
    t.string   "mission"
    t.datetime "created_at",  null: false
    t.datetime "updated_at",  null: false
  end

  create_table "organizations_users", force: :cascade do |t|
    t.integer  "user_id"
    t.integer  "organization_id"
    t.datetime "created_at",      null: false
    t.datetime "updated_at",      null: false
  end

  create_table "users", force: :cascade do |t|
    t.string   "email",                  default: "", null: false
    t.string   "encrypted_password",     default: "", null: false
    t.string   "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    t.integer  "sign_in_count",          default: 0,  null: false
    t.datetime "current_sign_in_at"
    t.datetime "last_sign_in_at"
    t.string   "current_sign_in_ip"
    t.string   "last_sign_in_ip"
    t.datetime "created_at",                          null: false
    t.datetime "updated_at",                          null: false
    t.string   "first_name"
    t.string   "last_name"
  end

以下是模型:

class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable

  has_many :organizations_users
  has_many :organizations, :through => :organizations_users

end

class Organization < ActiveRecord::Base
  has_many :organizations_users
  has_many :users, :through => :organizations_users
  has_many :categories, as: :categorizable

end

class OrganizationsUser < ActiveRecord::Base
  belongs_to :user 
  belongs_to :organization
end

当我通过我的表单创建一个新组织时,它会充分创建。但是,由于某种原因,通过我的表单提交时,关系没有得到保存。

例如,如果我这样做:

o = Organization.last
o.users

我得到一个空的查询集:

  User Load (0.3ms)  SELECT "users".* FROM "users" INNER JOIN "organizations_users" ON "users"."id" = "organizations_users"."user_id" WHERE "organizations_users"."organization_id" = $1  [["organization_id", 11]]
 => #<ActiveRecord::Associations::CollectionProxy []>

这是我的表格:

<%= form_for(@organization) do |f| %>
  <% if @organization.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@organization.errors.count, "error") %> prohibited this organization from being saved:</h2>

      <ul>
      <% @organization.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="form-group">
    <%= f.label :name %><br>
    <%= f.text_field :name, class:"form-control", autofocus: true %>
  </div>
  <div class="form-group">
    <%= f.label :description %><br>
    <%= f.text_field :description, class:"form-control", autofocus: true %>
  </div>
  <div class="form-group">
    <%= f.label :mission %><br>
    <%= f.text_field :mission, class:"form-control", autofocus: true %>
  </div>
  <div class="actions">
    <%= f.submit "Submit", class:"btn btn-primary" %>
  </div>
<% end %>

这是我的控制器:

class OrganizationsController < ApplicationController

  before_action :set_organization, only: [:show, :edit, :update, :destroy]

  # GET /organizations
  # GET /organizations.json
  def index
    @organizations = Organization.all.paginate(:page => params[:page], :per_page => 10)
  end

  # GET /organizations/1
  # GET /organizations/1.json
  def show
  end

  # GET /organizations/new
  def new
    @organization = Organization.new
  end

  # GET /organizations/1/edit
  def edit
  end

  # POST /organizations
  # POST /organizations.json
  def create
    @organization = Organization.new(organization_params)

    respond_to do |format|
      if @organization.save
        format.html { redirect_to @organization, notice: 'Organization was successfully created.' }
        format.json { render :show, status: :created, location: @organization }
      else
        format.html { render :new }
        format.json { render json: @organization.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /organizations/1
  # PATCH/PUT /organizations/1.json
  def update
    respond_to do |format|
      if @organization.update(organization_params)
        format.html { redirect_to @organization, notice: 'Organization was successfully updated.' }
        format.json { render :show, status: :ok, location: @organization }
      else
        format.html { render :edit }
        format.json { render json: @organization.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /organizations/1
  # DELETE /organizations/1.json
  def destroy
    @organization.destroy
    respond_to do |format|
      format.html { redirect_to organizations_url, notice: 'Organization was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_organization
      @organization = Organization.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def organization_params
      params.require(:organization).permit!
    end
end

奇怪的是,我使用 Faker gem 创建了一些种子数据,当我通过我的 rails 控制台执行相同的查询时,以这种方式创建的组织似乎返回了一个用户。所以接线是正确的,但我的表单或参数一定有问题?

这就是我成功创建组织的方式,该组织通过种子数据关联了一个用户:

for n in 1..10 do
  user = User.create!(
    first_name: Faker::Name.first_name, 
    last_name: Faker::Name.last_name,
    email: Faker::Internet.email, 
    password: "password",
    employer: Faker::University.name,
    title: Faker::Name.title,
    short_bio: Faker::Lorem.paragraph)
  user.organizations.create!(
    name: Faker::Company.name, 
    description: Faker::Lorem.paragraph, 
    mission: Faker::Lorem.sentence)
end

为什么会这样?关系仅通过表格不起作用我在这里误解了什么吗?

【问题讨论】:

  • 也许这会有所帮助:autosave: true 选项呢?如果没有此选项,您必须在每次更新关系时显式保存对象。

标签: ruby-on-rails ruby ruby-on-rails-4 activerecord model-view-controller


【解决方案1】:

我通过这样做解决了它:

u = current_user
o = u.organizations.build(name:'blah')
u.save
o.save

出于某种原因,必须保存两个对象以保存关系。不知道为什么。

控制器中有这样的东西:

  def create
    @user = current_user
    @organization = @user.organizations.build(organization_params)  

    respond_to do |format|
      if @user.save && @organization.save

【讨论】:

  • 缺少:autosave =&gt; true
【解决方案2】:

您可能只想手动创建连接表。这不是最好的方法,但既然你被卡住了,也许它至少可以帮助你滚动。

@organization = Organization.new(organization_params)
OrganizationsUser.create(
  user_id: current_user.id, organization_id: @organization.id
)

【讨论】:

  • 这不起作用。 @organization 没有 user_id 列....我错过了什么吗?
  • 嗯...看起来它的构建方式与我想象的不同。我看了一下架构。对您而言,organizations_user 是什么?它与用户不同,还是只是某些用户是organization_user?您不需要为此使用不同的表,只需 organizationuser 上的列。查看我的更新答案。
  • 对,但为什么需要通过?您是否有不想使用 has_many 的原因?和belongs_to?
  • 因为 1 个用户可以是多个组织的一部分,而一个组织可以有多个用户...
  • 任何用户都可以通过表单创建组织,但不一定是组织中唯一的一部分。其他人可以在以后随时加入该组织。
【解决方案3】:

您没有在控制器的 create 方法中创建关系。您目前拥有:

@organization = Organization.new(organization_params)

您应该像在种子文件中创建它一样创建它:

@user = #find your user here
@organization = @user.organizations.new(organization_params)

这应该会创建您的组织和关系。

【讨论】:

  • 这也不起作用,当我在新创建的组织实例上调用 .users 时,它仍然给我一个空集合
  • 您的用户记录是否保存到数据库中?
  • 我在我自己的答案下面发布了我如何让它工作的答案。这似乎有点骇人听闻,但它确实有效....
  • 你不应该这样做。这是在测试中吗?
  • 我用控制器代码编辑了我的答案。不,它不在测试中。这是让它工作的唯一方法。我不知道为什么我必须这样做,但除非我这样做,否则它不起作用。任何其他建议表示赞赏。
猜你喜欢
  • 1970-01-01
  • 2013-11-24
  • 2016-08-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多