2012-01-11 11 views
48

मैं एकाधिक चयन के साथ एक पोस्ट के लिए कई श्रेणियों का चयन करने की संभावना प्राप्त करना चाहता हूं।रेल 3: एसोसिएशन के माध्यम से has_many के साथ एकाधिक चयन

मेरे पास अगले मॉडल हैं: पोस्ट, श्रेणी और पोस्ट श्रेणी।

class Post < ActiveRecord::Base 
    has_many :post_categories 
    has_many :categories, :through => :post_categories 
end 

class Category < ActiveRecord::Base 
    has_many :post_categories 
    has_many :posts, :through => :post_categories 
end 

class PostCategory < ActiveRecord::Base 
    has_one :post 
    has_one :category 
    belongs_to :post  # foreign key - post_id 
    belongs_to :category # foreign key - category_id 
end 

मेरे नियंत्रक में मेरे पास @post = post.new की तरह कुछ है। मैंने कुछ श्रेणियां बनाई हैं।

और ध्यान में रखते हुए मैं:

<%= form_for @post do |f| %> 
    <%= f.text_field :title %> 
    <%= f.select :categories, :multiple => true %> 
    <%= f.submit %> 
<% end %> 

और ... जहाँ मेरे श्रेणियों है? मेरे पास चुनिंदा विकल्पों में केवल "एकाधिक" है। मुझे लगता है कि यह मेरे रूप में कुछ गलत है।

+0

अब मैं '<% = select_tag" श्रेणियों ", options_from_collection_for_select (Categories.all, 'आईडी', 'नाम'),: एकाधिक => सही%> '। और नियंत्रक की "निर्माण" कार्रवाई में मेरे पास @ @ पोस्ट = पोस्ट.न्यू (पैराम्स [: पोस्ट]) है। PostCategory में मुझे नए रिकॉर्ड बनाने की क्या ज़रूरत है? –

उत्तर

117

क्षमा मृत फिर से शुरू करने के लिए, लेकिन मैं एक बहुत सरल समाधान एक डिफ़ॉल्ट नियंत्रक कार्रवाई कोड का उपयोग करें और एक has_many के लिए ActiveModel सेटर तर्क का उपयोग करने देता है कि मिल गया। हाँ, यह पूरी तरह से जादू है।

<%= f.select :category_ids, Category.all.collect {|x| [x.name, x.id]}, {}, :multiple => true %> 

विशेष रूप से, का उपयोग करते हुए: category_ids (या: your_collection_ids) परम नाम स्वतः @ post.category_ids = params कॉल करने के लिए रेल बता देंगे [: पोस्ट] [: category_ids] तदनुसार कि इस पद के लिए श्रेणियों स्थापित करने के लिए सभी, डिफ़ॉल्ट नियंत्रक/मचान #create और #update कोड को संशोधित किए बिना।

ओह, और यह has_many के साथ काम करता है: कुछ, के माध्यम से:: something_else, स्वचालित रूप से शामिल मॉडल का प्रबंधन। भयानक गुस्सा।

तो ओपी से, केवल फ़ील्ड/पैराम नाम को श्रेणियों के बजाय श्रेणी_ids में बदलें: श्रेणियां।

यह स्वचालित रूप से मॉडल के चयनित श्रेणियों को भी चयन फ़ील्ड पर हाइलाइट किए गए चुनिंदा फ़ील्ड को पॉप्युलेट करेगा।

संदर्भ:

From the has_many API docs जहां मैं इस पाया।

the warning from the form helpers guide उचित फॉर्म-फ़ील्ड/पैरामीटर नाम का उपयोग न करने पर इस "टाइप मिस्चैच" को समझाता है।

उचित फॉर्म-फ़ील्ड/पैराम नाम का उपयोग करके, आप नए सूख सकते हैं और फॉर्म संपादित कर सकते हैं और नियंत्रकों को पतले रख सकते हैं, जैसा कि रेल मार्ग द्वारा प्रोत्साहित किया जाता है। रेल 4 और मजबूत मापदंडों के लिए

ध्यान दें:

def post_params 
    params.require(:post).permit(:title, :body, category_ids: []) 
end 
+0

धन्यवाद! मुझे पता था कि यह रेल 3 :-) – gernberg

+0

@winfred में काम करने के लिए एक आसान और सुरुचिपूर्ण तरीका होना चाहिए था। मेरे पास पोस्ट के साथ 'has_one' संबंध है, सिवाय इसके कि मेरे पास लगभग एक ही सेटअप है। क्या 'has_many' की' name_ids' विधि के लिए कोई 'है_ऑन 'बराबर है? – cyreb7

+0

@ cyreb7 मुझे विश्वास है कि "श्रेणी_आईडी" होगा। = -) – winfred

0

जैसा कि @ पोस्ट में आईडी नहीं है, हो सकता है कि हो सकता है कि श्रेणियां प्रदर्शित न हों क्योंकि कोई सहयोग नहीं है। आप

@post = Post.new(:categories => Category.all) 
+0

उत्तर के लिए धन्यवाद। "बिल्ड" के साथ मेरे पास "अपरिभाषित विधि 'बिल्ड' है ..." त्रुटि :( –

+0

ऐसा इसलिए है क्योंकि ऐसी कोई विधि नहीं है। यह केवल एसोसिएशन पर उपलब्ध है .. उसका मतलब पोस्ट.न्यू (: श्रेणियां => category.all) लेकिन इसका मतलब है कि आपकी पोस्ट सभी श्रेणियों को शामिल करने के लिए शुरू की गई है। – Tigraine

+0

हां, यह नई के साथ कोई त्रुटि नहीं है। लेकिन ... हाँ :) –

1

आपको क्या करना होगा चयन के लिए विकल्प की एक सूची है की तरह @post कुछ पर निर्माण कर पारित करने के लिए की जरूरत है:

<%= f.select :category_id, Category.all.collect {|x| [x.name, x.id]}, :multiple => true %> 
+0

धन्यवाद! सभी श्रेणियां अब चुनने के लिए उपलब्ध हैं ... लेकिन एकाधिक चयन के लिए नहीं :) यदि आपके पास कोई विचार है तो मैं आभारी रहूंगा। –

+0

मैं पहले अपने उत्तर में एकाधिक => सच भूल गया .. मैंने इसे एक घंटे पहले अपडेट किया था या तो .. – Tigraine

+0

या यह शायद हो सकता है: html => {: multi => true} – Tigraine

10

अंतिम समाधान अपनी पोस्ट में श्रेणीबद्ध करने के लिए, मैं यह आशा उपयोगी हो जाएगा।

कई का उपयोग करने के लिए हम select_tag की जरूरत है: (! Tigraine और ब्रेंट करने के लिए बहुत धन्यवाद)

<%= select_tag "categories", options_from_collection_for_select(Categories.all, 'id', 'name'), :multiple => true %> 

या f.select, इसे और अधिक सुंदर तरीका है:

<%= f.select :categories, Category.all.collect {|x| [x.name, x.id]}, {}, :multiple => true %> 

में की कार्रवाई बनाने हमारे नियंत्रक की हमें आवश्यकता है:

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

if @post.save 

    params[:categories].each do |categories| 
    categories = PostCategory.new(:category_id => categories, :post_id => @post.id) 
    if categories.valid? 
     categories.save 
    else 
     @errors += categories.errors 
    end 
    end 
    redirect_to root_url, :notice => "Bingo!" 
else 
    render "new" 
end 
end 
1

टिग्रेन लगभग था, लेकिन आप एक अतिरिक्त खाली हैश निर्दिष्ट करना होगा:

<%= f.select :category_id, Category.all.collect {|x| [x.name, x.id]}, {}, :multiple => true %>

+0

यह खाली हैश के साथ काम करता है, धन्यवाद! लेकिन मेरे मामले में: category_id होगा: श्रेणियां। –

+0

के लिए खाली हैश क्या है? – vipin8169

संबंधित मुद्दे