14

मैं एक सुंदर आम (जैसा मैंने सोचा था) हल करने की कोशिश कर रहा हूं।रेल के पास चेकबॉक्स के साथ फॉर्म के माध्यम से है और मॉडल में शामिल क्षेत्र में अतिरिक्त फ़ील्ड

तीन मॉडलों वहाँ कर रहे हैं:

class Product < ActiveRecord::Base 
    validates :name, presence: true 

    has_many :categorizations 
    has_many :categories, :through => :categorizations 

    accepts_nested_attributes_for :categorizations 
end 

class Categorization < ActiveRecord::Base 
    belongs_to :product 
    belongs_to :category 

    validates :description, presence: true # note the additional field here 
end 

class Category < ActiveRecord::Base 
    validates :name, presence: true 
end 

मेरे समस्याओं शुरू जब यह उत्पाद नई/संपादित रूप में आता है।

कोई उत्पाद बनाते समय मुझे श्रेणियों (चेकबॉक्स के माध्यम से) की जांच करने की आवश्यकता होती है, जो यह संबंधित है। मुझे पता है कि यह 'product [category_ids] []' जैसे नाम वाले चेकबॉक्स बनाकर किया जा सकता है। लेकिन मुझे प्रत्येक चेक किए गए रिश्तों के लिए विवरण दर्ज करने की भी आवश्यकता है जो शामिल मॉडल (वर्गीकरण) में संग्रहीत किया जाएगा।

मैंने जटिल रूपों, habtm चेकबॉक्स आदि पर उन खूबसूरत Railscasts को देखा, मैं शायद ही कभी StackOverflow खोज रहा हूं। लेकिन मैं सफल नहीं हुआ है।

मुझे एक post मिला जो लगभग मेरे जैसा ही समस्या का वर्णन करता है। और आखिरी जवाब मुझे कुछ समझ में आता है (ऐसा लगता है कि यह जाने का सही तरीका है)। लेकिन यह वास्तव में अच्छी तरह से काम नहीं कर रहा है (यानी अगर सत्यापन विफल रहता है)। मैं हमेशा एक ही क्रम में श्रेणियों को प्रदर्शित करना चाहता हूं (नए/संपादन रूपों में; सत्यापन के पहले/बाद में) और सत्यापन बॉक्स विफल होने पर चेकबॉक्स जहां वे थे, आदि

किसी भी सामान की सराहना की। मैं रेल के लिए नया हूं (केकेपीएचपी से स्विचिंग) तो कृपया धैर्य रखें और जितना संभव हो उतना विस्तृत लिखें। कृपया मुझे सही तरीके से इंगित करें!

धन्यवाद। :)

उत्तर

26

लग रहा है अंदर की तरह मैं यह पता लगा! यहाँ मैं क्या मिला है:

मेरे मॉडल:

class Product < ActiveRecord::Base 
    has_many :categorizations, dependent: :destroy 
    has_many :categories, through: :categorizations 

    accepts_nested_attributes_for :categorizations, allow_destroy: true 

    validates :name, presence: true 

    def initialized_categorizations # this is the key method 
    [].tap do |o| 
     Category.all.each do |category| 
     if c = categorizations.find { |c| c.category_id == category.id } 
      o << c.tap { |c| c.enable ||= true } 
     else 
      o << Categorization.new(category: category) 
     end 
     end 
    end 
    end 

end 

class Category < ActiveRecord::Base 
    has_many :categorizations, dependent: :destroy 
    has_many :products, through: :categorizations 

    validates :name, presence: true 
end 

class Categorization < ActiveRecord::Base 
    belongs_to :product 
    belongs_to :category 

    validates :description, presence: true 

    attr_accessor :enable # nice little thingy here 
end 

प्रपत्र:

<%= form_for(@product) do |f| %> 
    ... 
    <div class="field"> 
    <%= f.label :name %><br /> 
    <%= f.text_field :name %> 
    </div> 

    <%= f.fields_for :categorizations, @product.initialized_categorizations do |builder| %> 
    <% category = builder.object.category %> 
    <%= builder.hidden_field :category_id %> 

    <div class="field"> 
     <%= builder.label :enable, category.name %> 
     <%= builder.check_box :enable %> 
    </div> 

    <div class="field"> 
     <%= builder.label :description %><br /> 
     <%= builder.text_field :description %> 
    </div> 
    <% end %> 

    <div class="actions"> 
    <%= f.submit %> 
    </div> 
<% end %> 

और नियंत्रक:

class ProductsController < ApplicationController 

    before_filter :process_categorizations_attrs, only: [:create, :update] 

    def process_categorizations_attrs 
    params[:product][:categorizations_attributes].values.each do |cat_attr| 
     cat_attr[:_destroy] = true if cat_attr[:enable] != '1' 
    end 
    end 

    ... 

    # all the rest is a standard scaffolded code 

end 

पहली नज़र में यह सिर्फ ठीक काम करता है से। मुझे आशा है कि यह किसी भी तरह से तोड़ नहीं देगा .. :)

धन्यवाद सब कुछ। चर्चा में भाग लेने के लिए संदीप रांसिंग के लिए विशेष धन्यवाद। मुझे उम्मीद है कि यह मेरे जैसे किसी के लिए उपयोगी होगा।

+1

अच्छी तरह से किया गया। मुझे लगता है कि एक आसान तरीका हो सकता है, हालांकि। – courtsimas

+0

साझा करने के लिए बहुत बहुत धन्यवाद, मुझे http://stackoverflow.com/a/15920542/148421 के साथ भी पूरक होना था क्योंकि मेरे मूल्य जहां सहेजे नहीं जा रहे थे और मैं याद कर रहा था कि नेस्टेड विशेषताओं को कैसे अनुमति दें – Andrea

1

उपयोग accepts_nested_attributes_forintermediate table अर्थात categorizations दृश्य रूप में डालने के लिए की तरह दिखाई देगा -

# make sure to build product categorizations at controller level if not already 
class ProductsController < ApplicationController 
    before_filter :build_product, :only => [:new] 
    before_filter :load_product, :only => [:edit] 
    before_filter :build_or_load_categorization, :only => [:new, :edit] 

    def create 
    @product.attributes = params[:product] 
    if @product.save 
     flash[:success] = I18n.t('product.create.success') 
     redirect_to :action => :index 
    else 
     render_with_categorization(:new) 
    end 
    end 

    def update 
    @product.attributes = params[:product] 
    if @product.save 
     flash[:success] = I18n.t('product.update.success') 
     redirect_to :action => :index 
    else 
     render_with_categorization(:edit) 
    end 
    end 

    private 
    def build_product 
    @product = Product.new 
    end 

    def load_product 
    @product = Product.find_by_id(params[:id]) 
    @product || invalid_url 
    end 

    def build_or_load_categorization 
    Category.where('id not in (?)', @product.categories).each do |c| 
     @product.categorizations.new(:category => c) 
    end 
    end 

    def render_with_categorization(template) 
    build_or_load_categorization 
    render :action => template 
    end 
end 

दृश्य

= form_for @product do |f| 
    = f.fields_for :categorizations do |c| 
    %label= c.object.category.name 
    = c.check_box :category_id, {}, c.object.category_id, nil 
    %label Description 
    = c.text_field :description 
+0

धन्यवाद! लेकिन ऐसा लगता है कि आपका समाधान सत्यापन और अन्य सामान के साथ अच्छा नहीं खेलता है। चेकबॉक्स हमेशा चेक किए जाते हैं और यहां तक ​​कि यदि मैं उन्हें अनचेक करता हूं तो इसे अनदेखा किया जाता है (वे विफल सत्यापन के बाद वापस आ गए हैं या यदि सत्यापन पास हो जाता है तो संबंध हटा दिए जाते हैं)। साथ ही मैं श्रेणियों को हमेशा एक ही क्रम में सूचीबद्ध करना चाहता हूं (उदाहरण के लिए आप उन उत्पादों के बाद बिना असाइन किए गए श्रेणियों को जोड़ रहे हैं जो पहले से ही उत्पाद से जुड़े हुए हैं)। कोई विचार? – ok32

+0

आप संग्रह '@ product.categorizations' –

+0

पर ऑर्डर कर सकते हैं क्या आप पैरामीटर को पारित कर सकते हैं? –

1

मैंने अभी निम्नलिखित किया है। यह मेरे लिए काम किया ..

<%= f.label :category, "Category" %> 
<%= f.select :category_ids, Category.order('name ASC').all.collect {|c| [c.name, c.id]}, {} %> 
+0

यह अतिरिक्त जुड़ाव की अनुमति नहीं देता है ओप के रूप में मॉडल क्षेत्र के लिए पूछा – dft

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