2015-09-23 94 views
1

我正在創建一家服裝店。我有分類有尺寸。女裝襯衫(類別)可能有XS,S,M,Large。男士襯衫可以有XS,S,M,L。鞋子可以有4-16等。Has_many通過:關聯category_sizes

我創建了一個has_many through: association,它將Category表與Sizes表連接起來,並由Cateogry_Sizes表連接。

當管理員創建一個類別時,他們應該選擇該類別需要的所有尺寸。

如何在下面的視圖中選擇尺寸?

當前的代碼不正確。在控制檯中,當我去category.sizes時,我只是得到一個空數組。

查看:

<div class="container"> 
    <div class=「row」> 
    <div class="col-md-6 col-md-offset-3"> 
     <div class="panel panel-primary"> 
     <div class="panel-body"> 
        <%= simple_form_for(@category) do |f| %> 
         <div class="form-inputs"> 
         <%= f.input :name %> 
       <%= f.select(:sizes, Size.all.map {|s| [s.title, s.id]}, :multiple => true) %> 
       <%= f.collection_select :parent_id, Category.order(:name), :id, :name, {prompt: "Select Parrent ID If Applicable"},include_blank: true %> 
       <div class="form-actions"><%= f.button :submit %></div> 
      </div> 
      <% end %> 
     </div> 
     </div> 
    </div> 
    </div> 
</div> 

分類模型:

class Category < ActiveRecord::Base 
    has_ancestry 
    has_many :items 
    validates :name, presence: true, length: { maximum: 20 } 
    has_many :category_sizes 
    has_many :sizes, through: :category_sizes 
end 

規格型號:

class Size < ActiveRecord::Base 
    validates :title, presence: true, length: { maximum: 15 } 
    validates :title, uniqueness: true 

    has_many :category_sizes 
    has_many :categories, through: :category_sizes 
end 

Category_size型號:

class CategorySize < ActiveRecord::Base 
    belongs_to :category 
    belongs_to :size 
end 

架構:

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

    create_table "categories", force: :cascade do |t| 
    t.string "name" 
    t.string "ancestry" 
    t.datetime "created_at", null: false 
    t.datetime "updated_at", null: false 
    end 

    add_index "categories", ["ancestry"], name: "index_categories_on_ancestry" 

    create_table "category_sizes", force: :cascade do |t| 
    t.integer "category_id" 
    t.integer "size_id" 
    t.datetime "created_at", null: false 
    t.datetime "updated_at", null: false 
    end 

    add_index "category_sizes", ["category_id"], name: "index_category_sizes_on_category_id" 
    add_index "category_sizes", ["size_id"], name: "index_category_sizes_on_size_id" 

    create_table "items", force: :cascade do |t| 
    t.string "title" 
    t.decimal "price" 
    t.text  "description" 
    t.datetime "created_at",   null: false 
    t.datetime "updated_at",   null: false 
    t.integer "user_id" 
    t.string "image_file_name" 
    t.string "image_content_type" 
    t.integer "image_file_size" 
    t.datetime "image_updated_at" 
    t.integer "category_id" 
    end 

    add_index "items", ["user_id", "created_at"], name: "index_items_on_user_id_and_created_at" 
    add_index "items", ["user_id"], name: "index_items_on_user_id" 

    create_table "sizes", force: :cascade do |t| 
    t.text  "title" 
    t.datetime "created_at", null: false 
    t.datetime "updated_at", null: false 
    end 

    create_table "taggings", force: :cascade do |t| 
    t.integer "tag_id" 
    t.integer "taggable_id" 
    t.string "taggable_type" 
    t.integer "tagger_id" 
    t.string "tagger_type" 
    t.string "context",  limit: 128 
    t.datetime "created_at" 
    end 

    add_index "taggings", ["tag_id", "taggable_id", "taggable_type", "context", "tagger_id", "tagger_type"], name: "taggings_idx", unique: true 
    add_index "taggings", ["taggable_id", "taggable_type", "context"], name: "index_taggings_on_taggable_id_and_taggable_type_and_context" 

    create_table "tags", force: :cascade do |t| 
    t.string "name" 
    t.integer "taggings_count", default: 0 
    end 

    add_index "tags", ["name"], name: "index_tags_on_name", unique: true 

    create_table "users", force: :cascade do |t| 
    t.string "username" 
    t.string "email" 
    t.datetime "created_at",       null: false 
    t.datetime "updated_at",       null: false 
    t.string "password_digest" 
    t.string "remember_digest" 
    t.boolean "admin",    default: false 
    t.string "activation_digest" 
    t.boolean "activated",   default: false 
    t.datetime "activated_at" 
    t.string "reset_digest" 
    t.string ">" 
    t.datetime "reset_sent_at" 
    t.string "avatar_file_name" 
    t.string "avatar_content_type" 
    t.integer "avatar_file_size" 
    t.datetime "avatar_updated_at" 
    t.text  "description" 
    end 

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

end 

控制器:

class CategoriesController < ApplicationController 
    before_action :set_category, only: [:show] 
    before_action :admin_user,  only: [:destroy, :index, :edit, :show] 

    def index 
    @categories = Category.all 
    end 

    def show 
    @tags = Item.where(category_id: @category.id).tag_counts_on(:tags) 
    if params[:tag] 
     @items = Item.tagged_with(params[:tag]) 
    else 
     @items = Item.where(category_id: @category.id).order("created_at DESC") 
    end 
    end 

    def new 
    @category = Category.new 
    end 

    def edit 
    @category = Category.find(params[:id]) 
    end 

    def create 
    @category = Category.new(category_params) 
    if @category.save 
     redirect_to @category 
     flash[:success] = "You have created a new category" 
    else 
     flash[:danger] = "Your category didn't save" 
     render "new" 
    end 
    end 

    def update 
    @Cateogry = Category.find(params[:id]) 
    if @Cateogry.update(category_params) 
     redirect_to @Cateogry 
     flash[:success] = 'Category was successfully updated.' 
    else 
     render "edit" 
    end 
    end 

    def destroy 
    Category.find(params[:id]).destroy 
    flash[:success] = "Category deleted" 
    redirect_to categories_path 
    end 

    private 

    def set_category 
     @category = Category.find(params[:id]) 
    end 

    def category_params 
     params.require(:category).permit(:name, :parent_id) 
    end 

    # Confirms an admin user. 
    def admin_user 
     redirect_to(root_url) unless current_user.try(:admin?) 
    end 

end 

下面是當控制檯會發生什麼:

2.1.2 :026 > c = Category.last 
    Category Load (0.3ms) SELECT "categories".* FROM "categories" ORDER BY "categories"."id" DESC LIMIT 1 
=> #<Category id: 57, name: "Test20", ancestry: "20", created_at: "2015-09-23 12:35:14", updated_at: "2015-09-23 12:35:14"> 
2.1.2 :027 > c.sizes 
    Size Load (0.2ms) SELECT "sizes".* FROM "sizes" INNER JOIN "category_sizes" ON "sizes"."id" = "category_sizes"."size_id" WHERE "category_sizes"."category_id" = ? [["category_id", 57]] 

這裏是形式會發生什麼提交在服務器日誌:

Started POST "/categories" for ::1 at 2015-09-23 22:37:28 +1000 
Processing by CategoriesController#create as HTML 
    Parameters: {"utf8"=>"✓", "authenticity_token"=>"4pMZ9PUr5yTSCNRiQeATljZsOIDeQCwhQPy9djEbAmejntpb8/DkK20JrMUeZkStsB5UU6YhbtExGwDKs7tT2Q==", "category"=>{"name"=>"test21", "sizes"=>"6", "parent_id"=>"20"}, "commit"=>"Create Category"} 
Unpermitted parameter: sizes 
    Category Load (0.1ms) SELECT "categories".* FROM "categories" WHERE "categories"."id" = ? LIMIT 1 [["id", 20]] 
    (0.1ms) begin transaction 
    SQL (0.3ms) INSERT INTO "categories" ("name", "ancestry", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["name", "test21"], ["ancestry", "20"], ["created_at", "2015-09-23 12:37:28.927360"], ["updated_at", "2015-09-23 12:37:28.927360"]] 
    (1.0ms) commit transaction 
Redirected to http://localhost:3000/categories/58 
Completed 302 Found in 5ms (ActiveRecord: 1.5ms) 


Started GET "/categories/58" for ::1 at 2015-09-23 22:37:28 +1000 
Processing by CategoriesController#show as HTML 
    Parameters: {"id"=>"58"} 
+0

在形式你可以看到所有可用的尺寸,你可以選擇它們並提交t他形成?你還可以顯示category_controller嗎? – IngoAlbers

+0

@EgonWilzer是的,我剛剛發佈了控制器。是的,現在我可以看到尺寸。 – joeyk16

回答

2

您需要al在這樣的控制器的PARAMS低大小:

def category_params 
     params.require(:category).permit(:name, :parent_id, size_ids: []) 
    end 

在你的表格,你或許應該改變:

<%= f.select(:sizes, Size.all.map {|s| [s.title, s.id]}, :multiple => true) %> 

<%= f.association :sizes %> 

簡單的形式則應該做的魔力。另見:https://github.com/plataformatec/simple_form#associations瞭解更多信息。

+0

謝謝我剛剛嘗試過,並創建了一個新的類別,並選擇了1個尺寸。當我運行category.sizes – joeyk16

+0

時,我發佈了結果,我只是將它從'sizes'更改爲'size_ids'。你試過了嗎?你可以看到表單提交中的服務器控制檯發生了什麼?是否有任何未經許可的參數消息? – IngoAlbers

+0

是的,我只是從表單提交服務器日誌,所以你可以看到。感謝堆。 – joeyk16

1

順便說一句,我覺得這很容易突出you may be able to use has_and_belongs_to_many使其目前的形式。它的工作原理非常相似,除了它has_many :through沒有加入模型:

#app/models/category.rb 
class Category < ActiveRecord::Base 
    has_and_belongs_to_many :sizes 
end 

#app/models/size.rb 
class Size < ActiveRecord::Base 
    has_and_belongs_to_many :categories 
end 

這將意味着你必須放棄你category_sizes表並categories_sizescategory_id | size_id列替換爲:

enter image description here

這是只有如果你不想在你的連接模型中包含任何進一步的信息,推薦使用。例如,如果您想要包含庫存水平或某物,那麼has_many :through的加入模式將至關重要;不像現在這樣。

它也可以讓你撥打:

@category = Category.find params[:id] 
@category.sizes #-> collection of sizes for category. 

-

HABTM也使形式更簡單:

<%= simple_form_for(@category) do |f| %> 
    <%= f.input :name %> 
    <%= f.collection_select :sizes, Size.all, :id, :name, { multiple: true } %> 
    <%= f.collection_select :parent_id, Category.order(:name), :id, :name, {prompt: "Select Parent ID If Applicable"},include_blank: true %> 
    <%= f.submit %> 
<% end %> 

#app/controllers/categories_controller.rb 
class CategoriesController < ApplicationController 
    def create 
     @category = Category.new category_params 
    end 

    private 

    def category_params 
     params.require(:category).permit(:etc, :etc, :sizes) 
    end 
end