2017-03-12 5 views
0

Ich bin ein Rails Newbie und Bau eine kleine Anwendung, um mit meiner Arbeit zu helfen.Schienen Formular collection_select nicht speichern in Datenbank

Ich habe Client, Site und Angebote Modelle und Controller mit Ansichten eingerichtet.

Ich habe ein Formular für das Angebotsmodell erstellt, das Daten aus den anderen beiden Modellen in ein collection_select-Feld zieht. Die Dokumentation von collection_select für Schienen, die ich gefunden habe, ist ziemlich schlecht. Ich möchte einen Clientnamen und einen Websitenamen verwenden und den Namen dem Angebot zuordnen/anzeigen.

Ich habe dies im Formular eingerichtet, aber es speichert nicht die Daten oder zeigt es.

Ich möchte wirklich die Eingaben für die Collection_select verstehen, da ich sicher bin, dass meine wahrscheinlich falsch sind und das Problem verursacht.

<%= f.collection_select :client, Client.all, :quote_client, :client_name , {:prompt => "Please select a client for the site"} %>

habe ich einige der Forschung und erfuhr von @juanpastas here

Meine Form wie so quotes/Ansichten sieht/_form.html

<%= form_for(quote) do |f| %> 
    <% if quote.errors.any? %> 
    <div id="error_explanation"> 
     <h2><%= pluralize(quote.errors.count, "error") %> prohibited this quote from being saved:</h2><ul> 
     <% quote.errors.full_messages.each do |message| %> 
     <li><%= message %></li> 
     <% end %> 
     </ul> 
    </div> 
    <% end %><div class="field"> 
    <%= f.label :client %> 
    <%= f.collection_select :client, Client.all, :quote_client, :client_name , {:prompt => "Please select a client for the site"} %> 
    </div><div class="field"> 
    <%= f.label :site_name %> 
    <%= f.collection_select :site, Site.all, :quote_site, :site_name , {:prompt => "Please select a site for the quote"} %> 
    </div><div class="field"> 
    <%= f.label :quote_contact %> 
    <%= f.text_field :quote_contact %> 
    </div><div class="field"> 
    <%= f.label :quote_value %> 
    <%= f.text_field :quote_value %> 
    </div><div class="field"> 
    <%= f.label :quote_description %> 
    <%= f.text_field :quote_description %> 
    </div><div class="actions"> 
    <%= f.submit %> 
    </div> 
<% end %> 

EDIT

Antworten/Klarstellungen

Angebote können nur einen Kunden und eine Website haben. Die Seite müsste auch dem Kunden gehören.

Ich habe eine Liste von Clients, die vom Client-Modell über Client.all aufgerufen werden, und eine Liste von Sites über das Site-Modell, das über Site.all aufgerufen wird. Ich brauche nur den Namen eines Kunden und eine Site für jedes Zitat, möchte aber kaskadierend auswählen können. Wählen Sie Client und dann Site aus den für den Client verfügbaren aus.

class Quote < ApplicationRecord 


      belongs_to :site, optional: true 
      belongs_to :client, optional: true 
      has_and_belongs_to_many :assets 
    end 

class Site < ApplicationRecord 


    has_attached_file :site_image, styles: { small: "64x64", med: "100x100", large: "200x200" } 
    do_not_validate_attachment_file_type :site_image 


    belongs_to :client , optional: true 
    has_and_belongs_to_many :assets 
    has_and_belongs_to_many :quotes 
end 

class Client < ApplicationRecord 

    has_and_belongs_to_many :sites 
    has_and_belongs_to_many :assets 
    has_and_belongs_to_many :quotes 
end 

Controller

class QuotesController < ApplicationController 
    before_action :set_quote, only: [:show, :edit, :update, :destroy] 

    # GET /quotes 
    # GET /quotes.json 
    def index 
    @quotes = Quote.all 
    end 

    # GET /quotes/1 
    # GET /quotes/1.json 
    def show 
    end 

    # GET /quotes/new 
    def new 
    @quote = Quote.new 
    end 

    # GET /quotes/1/edit 
    def edit 
    end 

    # POST /quotes 
    # POST /quotes.json 
    def create 
    @quote = Quote.new(quote_params) 

    respond_to do |format| 
     if @quote.save 
     format.html { redirect_to @quote, notice: 'Quote was successfully created.' } 
     format.json { render :show, status: :created, location: @quote } 
     else 
     format.html { render :new } 
     format.json { render json: @quote.errors, status: :unprocessable_entity } 
     end 
    end 
    end 

    # PATCH/PUT /quotes/1 
    # PATCH/PUT /quotes/1.json 
    def update 
    respond_to do |format| 
     if @quote.update(quote_params) 
     format.html { redirect_to @quote, notice: 'Quote was successfully updated.' } 
     format.json { render :show, status: :ok, location: @quote } 
     else 
     format.html { render :edit } 
     format.json { render json: @quote.errors, status: :unprocessable_entity } 
     end 
    end 
    end 

    # DELETE /quotes/1 
    # DELETE /quotes/1.json 
    def destroy 
    @quote.destroy 
    respond_to do |format| 
     format.html { redirect_to quotes_url, notice: 'Quote was successfully destroyed.' } 
     format.json { head :no_content } 
    end 
    end 

    private 
    # Use callbacks to share common setup or constraints between actions. 
    def set_quote 
     @quote = Quote.find(params[:id]) 
    end 

    # Never trust parameters from the scary internet, only allow the white list through. 
    def quote_params 
     params.require(:quote).permit(:quote_client, :quote_site, :client_name, :site_name, :quote_contact, :quote_value, :quote_description) 
    end 
end 


class SitesController < ApplicationController 
    before_action :set_site, only: [:show, :edit, :update, :destroy] 

    # GET /sites 
    # GET /sites.json 
    def index 
    @sites = Site.all 
    @clients = Client.all 
    end 

    # GET /sites/1 
    # GET /sites/1.json 
    def show 
     @sites = Site.all 
     @clients = Client.all 
    end 

    # GET /sites/new 
    def new 
    @site = Site.new 
    end 

    # GET /sites/1/edit 
    def edit 
    end 

    # POST /sites 
    # POST /sites.json 
    def create 
    @site = Site.new(site_params) 

    respond_to do |format| 
     if @site.save 
     format.html { redirect_to @site, notice: 'Site was successfully created.' } 
     format.json { render :show, status: :created, location: @site } 
     else 
     format.html { render :new } 
     format.json { render json: @site.errors, status: :unprocessable_entity } 
     end 
    end 
    end 

    # PATCH/PUT /sites/1 
    # PATCH/PUT /sites/1.json 
    def update 
    respond_to do |format| 
     if @site.update(site_params) 
     format.html { redirect_to @site, notice: 'Site was successfully updated.' } 
     format.json { render :show, status: :ok, location: @site } 
     else 
     format.html { render :edit } 
     format.json { render json: @site.errors, status: :unprocessable_entity } 
     end 
    end 
    end 

    # DELETE /sites/1 
    # DELETE /sites/1.json 
    def destroy 
    @site.destroy 
    respond_to do |format| 
     format.html { redirect_to sites_url, notice: 'Site was successfully destroyed.' } 
     format.json { head :no_content } 
    end 
    end 

    private 
    # Use callbacks to share common setup or constraints between actions. 
    def set_site 
     @site = Site.find(params[:id]) 
    end 

    # Never trust parameters from the scary internet, only allow the white list through. 
    def site_params 
     params.require(:site).permit(:site_client, :client_name, :site_name, :site_image, :site_address, :site_contact) 
    end 
end 

class ClientsController < ApplicationController 
    before_action :set_client, only: [:show, :edit, :update, :destroy] 

    # GET /clients 
    # GET /clients.json 
    def index 
    @clients = Client.all 
    @sites = Site.all 
    end 

    # GET /clients/1 
    # GET /clients/1.json 
    def show 
     @clients = Client.all 
     @sites = Site.all 
    end 

    # GET /clients/new 
    def new 
    @client = Client.new 
    end 

    # GET /clients/1/edit 
    def edit 
    end 

    # POST /clients 
    # POST /clients.json 
    def create 
    @client = Client.new(client_params) 

    respond_to do |format| 
     if @client.save 
     format.html { redirect_to @client, notice: 'Client was successfully created.' } 
     format.json { render :show, status: :created, location: @client } 
     else 
     format.html { render :new } 
     format.json { render json: @client.errors, status: :unprocessable_entity } 
     end 
    end 
    end 

    # PATCH/PUT /clients/1 
    # PATCH/PUT /clients/1.json 
    def update 
    respond_to do |format| 
     if @client.update(client_params) 
     format.html { redirect_to @client, notice: 'Client was successfully updated.' } 
     format.json { render :show, status: :ok, location: @client } 
     else 
     format.html { render :edit } 
     format.json { render json: @client.errors, status: :unprocessable_entity } 
     end 
    end 
    end 

    # DELETE /clients/1 
    # DELETE /clients/1.json 
    def destroy 
    @client.destroy 
    respond_to do |format| 
     format.html { redirect_to clients_url, notice: 'Client was successfully destroyed.' } 
     format.json { head :no_content } 
    end 
    end 

    private 
    # Use callbacks to share common setup or constraints between actions. 
    def set_client 
     @client = Client.find(params[:id]) 
    end 

    # Never trust parameters from the scary internet, only allow the white list through. 
    def client_params 
     params.require(:client).permit(:client_name, :client_address, :client_phone, :client_email, :client_website) 
    end 
end 

Zugänge

Sie können feststellen, ich so zu skalieren haben versucht, dass ein Client in genannt wird:

Beziehungen zwischen den drei Modellen wie so einrichten Eine Site und eine Site und ein Client werden in einem Zitat aufgerufen.

Antwort

0

Zunächst einmal: Ich nehme an, Sie haben Beziehungen zwischen den drei Modellen eingerichtet! Es muss eine has_many-Beziehung vom Angebot zum Kunden und vom Angebot zur Website geben.

Es gibt zwei Probleme, die das Speichern Ihres Formulars verhindern können.

Zunächst ist es in wie Sie Ihre Sammlung_Select erstellen. Der dritte Parameter in der Sammlungsauswahl ist, was an den Controller gesendet wird. Dies sollte ein Array von IDs sein (ich nehme an, ein Angebot kann mehr als einen Client haben). Ich sehe, du nennst es: quote_client. Ich würde es umbenennen zu: client_ids. Am Ende möchten Sie an Ihren Controller senden: ein Array von IDs.

Die zweite Sache, um die Sie sich kümmern müssen, ist Ihr Controller. Es wäre nett, wenn Sie Ihren Controller-Code teilen würden, aber ich nehme an, Sie haben einen quotes_controller mit einer quote_params-Methode darin.Es wird wahrscheinlich so aussehen:

def quote_params 
     params.require(:quote).permit(:quote_contact, etc., etc.) 
    end 

Dieses Controller-Methode mit Ihrem form_for reagieren, so dass jedes Feld in Ihrer form_for (wie quote_contact) in der Genehmigung sein sollte, sonst wird es nicht gerettet werden. Wenn Sie ein Array von IDs speichern möchten, müssen Sie dieser Methode mitteilen, dass Sie ein Array von IDs erwarten. Sie können das so tun: client_ids: [].

So wird Ihre neue quote_params Methode sollte wie folgt aussehen:

def quote_params 
    params.require(:quote).permit(:quote_contact, client_ids: [], site_ids: [], all_other_fields...) 
end 

Ich hoffe, diese Antwort, die Sie mit Ihrer dringend benötigten Hilfe zur Verfügung stellt. Wenn ich mehr klären müssen: einfach fragen :)

Prost

EDIT: die Antwort oben ist immer noch relevant für diejenigen, die mehrere Datensätze speichern wollen, sondern weil Sie gesagt Sie wollen nur einen Datensatz speichern Hier ist meine aktualisierte Antwort:

Die Logik, die ich oben summiert bleibt etwa gleich.

Was Sie im Moment nicht zu verstehen scheinen und was (IMO) für das Verständnis von Rails-Anwendungen sehr wichtig ist, ist die Art und Weise, wie Formulare den Controllern und Controllern der Datenbank zugeordnet werden. Die Methode quote_params sollte, wie oben erwähnt, alle Felder von Formularen zulassen, die Sie in der Datenbank speichern möchten. Dies bedeutet, dass alle Felder in Ihrem Genehmigungsteil in Ihrer Datenbank sein sollten, andernfalls können sie nicht gespeichert werden. Wenn Sie sich Ihre Quote-Tabelle in der Datenbank genau ansehen, werden Sie feststellen, dass sie Felder für client_id und site_id enthält. Diese beiden Felder enthalten die Referenz für Ihre Zitate/Kunden und Zitate/Site-Verknüpfungen. Aus diesem Grund funktioniert Ihre Genehmigung derzeit nicht, da Sie quote_client und quote_site an Ort und Stelle haben. Die Datenbank hat keinen quote_client oder quote_site und aktualisiert daher beim Speichern nicht die Verknüpfungen. Die Datenbank hat client_id und site_id, also sollten Sie diese an Ihre quote params Methode weitergeben.

Dies sollte natürlich den Feldern in Ihrem form_for entsprechen. Sie müssen also zwei Dinge ändern, um diese Arbeit zu machen:

  1. ändern zwei collection_selects und Swap-:quote_client für :client_id und :quote_site für :site_id.

  2. Ändern Sie Ihre Controller-Methode, um die Änderungen in Ihrem form_for widerzuspiegeln. Auch hier müssen Sie quote_site und quote_client für quote_id und site_id tauschen, wie folgt aus:

    def quote_params params.require(:quote).permit(:client_id, :site_id, etc.) end

Die wichtige Sache zu erinnern, wenn Rails MODELNAME_params Methoden (die wir starke Parameter nennen -> LESEN SIE ES! http://edgeguides.rubyonrails.org/action_controller_overview.html) ist, dass sowohl Ihr Formular als auch Ihre Erlaubnis Aktion die Felder genau wie sie in der Datenbank sind auflisten sollte, sonst wird die Datenbank nicht verstehen und Ihr Datensatz wird nicht ordnungsgemäß gespeichert.

Ich hoffe, mit dieser Bearbeitung werden Sie es herausfinden.

Prost

+0

Danke @WouterRonteltap, Sie waren eine große Hilfe. Ich habe weitere Informationen für Sie hinzugefügt, einschließlich der Controller für jeden. –

+0

Ich habe meinen Beitrag über das Erreichen Ihrer Sammlung bearbeitet Problem auswählen, hoffe, dass Sie es jetzt herausfinden :) –

+0

Etwas anderes: könnten Sie mir Ihr Datenbankschema zeigen? (db/schema.rb in Ihrem Projekt). In Ihrer Form_für Sie haben Werte wie Zitat_Beschreibung, aber ist es nicht in der DB wie Beschreibung gespeichert? oder haben Sie alle Felder quote_xxx benannt? (In diesem Fall ist es in Ordnung, aber es scheint mir wie eine seltsame Praxis) –

Verwandte Themen