简体   繁体   中英

Rails 4 form select from relational model

I'm not sure what I'm doing wrong here. Basically, users can only be created by an existing user and they can only be in a company that the existing user is in. So I want the f.select for :company to be from current_user.companies. The models are joined through table "users_companies".

Form:

  <div class="row">
    <h3>Add User</h3>
    <div class="column">
      <%= simple_form_for @user do |f| %>
        <%= f.input :name %>
        <%= f.input :email %>
        <%= f.select(:company_id, @companies.map {|company| [company,company]}) %>
        <%= f.select(:role, User.roles.keys.map {|role| [role,role]}) %>
        <%= f.input :password %>
        <%= f.input :password_confirmation %>
        <%= f.button :submit %>
      <% end %>
    </div>

Controller:

  def new
    @user = User.new
    @companies = current_user.companies
  end

  def create
    @user = User.new(params[:user].permit(:name, :company, :email, :role, :password, :password_confirmation))
    authorize @user
    @companies = current_user.companies

    if params[:user][:password].blank?
      params[:user].delete(:password)
      params[:user].delete(:password_confirmation)
    end

    respond_to do |format|
      if @user.save
        format.html { redirect_to users_path, notice: 'User was successfully created.' }
      else
        format.html { render action: "new" }
      end
    end
  end

Schema:

ActiveRecord::Schema.define(version: 20140620190817) do

  create_table "companies", force: true do |t|
    t.string   "name"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  create_table "groups", force: true do |t|
    t.string   "name"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.integer  "company_id"
    t.integer  "tag_id"
    t.integer  "q_rcode_id"
    t.integer  "page_id"
  end

  create_table "pages", force: true do |t|
    t.string   "name"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.integer  "company_id"
    t.integer  "group_id"
    t.integer  "tag_id"
    t.integer  "q_rcode_id"
  end

  create_table "q_rcodes", force: true do |t|
    t.string   "url"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.integer  "company_id"
    t.integer  "group_id"
    t.integer  "page_id"
  end

  create_table "tags", force: true do |t|
    t.string   "url"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.integer  "company_id"
    t.integer  "group_id"
    t.integer  "page_id"
  end

  create_table "users", force: true 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"
    t.datetime "updated_at"
    t.string   "name"
    t.integer  "role"
  end

  add_index "users", ["email"], name: "index_users_on_email", unique: true
  add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true

  create_table "users_companies", id: false, force: true do |t|
    t.integer "user_id"
    t.integer "company_id"
  end

  add_index "users_companies", ["user_id", "company_id"], name: "index_users_companies_on_user_id_and_company_id"
  add_index "users_companies", ["user_id"], name: "index_users_companies_on_user_id"

end

Okay, there is a problem. If the user and company have a many-to-many relationship through user_company, there is no way to tell when the user is the 'owner' of the company and when the user is the 'employee' of the company. You need two different associations.

Add user_id to Company

Add belongs_to association to Company model

class Company < ActiveRecord::Base
  has_many :users, :through => :company_user #these are the employees of the company
  belongs_to: :user #this is the user who owns the company
end

Fix your company_user data so that it only contains records where user is employee of the company

Fix your company data so user_id field contains the id of the user who is owner of the company

Your User model should already have a companies association

 class User < ActiveRecord::Base
          has_many :companies, :through => :company_user #these are the companies the user is employeed by
        end
  • Now '@companies' in your new action will have the list of companies the user is employeed by.

I figured it out without having to change the models. I ended up using the collection_select method as such:

<div class="row">
  <h3>Add User</h3>
  <div class="column">
    <%= simple_form_for @user do |f| %>
      <%= f.input :name %>
      <%= f.input :email %>
      <%= collection_select(:user, :company_ids, 
        current_user.companies, :id, :name) %>
      <%= f.select(:role, User.roles.keys.map {|role| [role,role]}) %>
      <%= f.input :password %>
      <%= f.input :password_confirmation %>
      <%= f.button :submit %>
    <% end %>
  </div>
</div>

And pulled out definitions from the controller, left with this:

  def create
    @user = User.new(params[:user].permit(:name, :company_ids, :email, :role, :password, :password_confirmation))
    authorize @user

    if params[:user][:password].blank?
      params[:user].delete(:password)
      params[:user].delete(:password_confirmation)
    end

    respond_to do |format|
      if @user.save
        format.html { redirect_to users_path, notice: 'User was successfully created.' }
      else
        format.html { render action: "new" }
      end
    end
  end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM