2017-01-05 5 views
6

In meiner Rails app ich Seiten, Blöcke, BlockContents, Felder und FieldContents.Speichern dynamische Felder in Rails

Die Verbände sind:

class Page < ActiveRecord::Base 
    has_many :blocks 
    has_many :block_contents, :through => :blocks 
end 

class Block < ActiveRecord::Base 
    belongs_to :page 
    has_many :block_contents 
end 

class BlockContent < ActiveRecord::Base 
    belongs_to :block 
    has_many :field_contents 
end 

class Field < ActiveRecord::Base 
    has_many :field_contents 
end 

class FieldContent < ActiveRecord::Base 
    belongs_to :block_content 
    belongs_to :field 
    validates :content, presence: true 
end 

diese Verwendung Ich bin in der Lage dynamische Felder für Seite zu haben.

jedoch an die DB Schreiben wird zur Zeit in der Steuerung wie dies getan:

def update 
    @page = Page.find(params[:id]) 
    if params[:field_content].present? 
    params[:field_content].each do |block_content| 
     block_content.last.each do |field| 
     field_content_row = FieldContent.where(block_content_id: block_content.first, field_id: field.first).first 
     if field_content_row.present? 
      field_content_row.update(content: field.last) 
     else 
      field_content = FieldContent.new 
      field_content.block_content_id = block_content.first 
      field_content.field_id = field.first 
      field_content.content = field.last 
      field_content.save 
     end 
     end 
    end 
    end 
    if @page.update_attributes(page_params) 
    redirect_to pages_path 
    else 
    render 'edit' 
    end 
end 

Während dies tut in Arbeit, es ist ziemlich schmutzig und es zeigt nicht meinen Validierungen für meinen FieldContent in der Ansicht (die Validierungen funktionieren, da sie den FieldContent nicht speichern, wenn sie ungültig sind, aber es sollte verhindern, dass die gesamte Seite gespeichert und in der Ansicht angezeigt wird.

Wie kann ich es so machen, dass ich die Validierungen für FieldContent zeigen können?


Für diejenigen, die die Ansicht sehen möchten:

<% @page.blocks.each do |block| %> 
    <% block.block_contents.each do |block_content| %> 
     <% field_group.fields.each do |field| %> 
      <input name="field_content[<%= block_content.id %>][<%= field.id %>]" id="field_content_<%= block_content.id %>_<%= field.id %>" type="text" value="<%= get_field_content(block_content, field.name) %>"> 
     <% end %> 
    <% end %> 
<% end %> 

und die Helfer Ich benutze den Inhalt zu erhalten:

def get_field_content(block_content, field) 
    content = '' 
    block_content.field_contents.each do |field_content| 
    if field_content.field.name == field && field_content.block_content_id == block_content.id 
     content = field_content.content 
    end 
    end 
    content 
end 
+0

Ich habe etwas ähnliches auf einer App vor 5 Jahren, die noch nützlich sein können. Fühlen Sie sich frei, die anderen Teile zu überprüfen, aber [die entsprechenden tidbit ist hier] (https://github.com/coreyward/talent-releases/blob/master/app/concerns/response_form.rb) mit dem Controller es die Integration [hier ] (https: // github.com/coreyward/Talent-Releases/Blob/Master/App/Controller/Releases_controller.rb # L149-L153). – coreyward

+0

@coreyward Das sieht interessant aus, aber ich bin ziemlich neu bei Ruby and Rails. Könnten Sie eine Antwort geben, die mehr erklärt, was Ihr Code tut? Ich nehme an, dass es Ihre Bedenken sind, Ihre Modelle so zu verknüpfen, dass die Speicherung gleichzeitig bei beiden Modellen erfolgt. – Cameron

+0

@coreyward Ich habe meinen Beitrag aktualisiert, um zu zeigen, wie die Ansicht auch aussieht. – Cameron

Antwort

2

Erstens, was Sie zunächst, um zu tun, um Senden Sie ein Formular, das mehrere Modelle enthält, um verschachtelte Attribute zu akzeptieren.

In Ihrer page.rb Datei setzen:

class Page < ActiveRecord::Base 
has_many :blocks 
has_many :block_contents, :through => :blocks 
accepts_nested_attributes_for :field_contents 

Zweitens in der Ansicht - Sie müssen angeben, welche Felder für das Modell 'fields_for' So in der form_for @ page verwenden, sollten Sie setzen:

<%= f.fields_for :field_contents do |b| %> 

Da: field_contents ist das einzige Objekt, das zusammen mit @page aktualisiert wird. So dass das Formelement in seiner Gesamtheit wie folgt aussieht:

<% @page.blocks.each do |block| %> 
    <% block.block_contents.each do |block_content| %> 
     <% field_group.fields.each do |field| %> 
      <%= form_for @page do |f| %> 
       <%= f.input :any attribute %> 
        <%= f.fields_for :field_contents do |b| %> 
         <%= b.text_field :content %> 
          <%= f.fields_for :block_contents do |b| %> 
           <%= b.hidden_field :block_content, value: "#{@block_content.id}"%> 
        <% end %> 
       <% end %> 
      <% end %> 
     <% end %> 
    <% end %> 
<% end %> 

Seit ich gelernt habe Sie schon @ page.field_content zugreifen kann, haben Sie nichts in der Steuerung zu berühren, wie es den Datensatz automatisch aktualisiert basierend auf der bestehenden Beziehung.

So, jetzt haben wir haben alle Modelle in einem einzigen Antrag gestellt wird festgelegt, dass Sie Fehlermeldungen in der Ansicht angezeigt werden soll nach der Validierung stattgefunden hat. Und das ist der einfache Teil.

Von dem, was ich sehen kann, sind die Validierung Sie derzeit die Anwesenheit von :content.

Ihrer Meinung: setzen Sie einfach ein HTML-Tag oder ein Schienen Inhalt Tag

<p class= "error"><%= "Your error message"if @field_content.errors[:content].present? %></p> 

Lassen Sie mich wissen, wenn Sie weitere Fragen haben.

+0

Ich folge dir nicht mit dem Sichtteil. Könnten Sie Ihr Beispiel erweitern, um zu zeigen, wie die Felder ausgeschrieben sind? Vielen Dank. – Cameron

+0

habe meine Antwort aktualisiert – Crashtor

+0

Woher kommt '@ blocks'? Die einzige Variable, die ich im Controller habe, ist '@ page'. Erzeugt '@ page.blocks.build' '@ blocks'? und muss ich auch einen für FieldContents und BlockContents im Controller machen? – Cameron