Domanda

Ho un'entità utente che ha un campo della posizione corrente (città e paese). Per mantenere queste informazioni ho creato un'entità chiamata Location che has_many utenti.

Io non sono del tutto sicuro se devo mettere nel modello User "has_one" o "belongs_to", ma per quello che ho letto, se ho voluto avere la chiave esterna della posizione devo mettere "belongs_to". Voglio anche essere in grado di modificare l'utente posizione corrente quando si modifica l'utente. così io sto usando attributi nidificati. Ma quando ho modificare l'utente finisco per l'aggiunta di una nuova posizione ogni volta senza mai associare all'utente che è stato modificato. Puoi aiutarmi?

Il mio codice è il seguente:

#User Model
class User < ActiveRecord::Base
  ## Relationships
  belongs_to :current_location, :class_name => 'Location'
  accepts_nested_attributes_for :current_location
end

#Location Model
class Location < ActiveRecord::Base
  #Relationship
  has_many :users
end

# part of the _form_edit.haml
- form_edit.fields_for :current_location do |location_form|
  = location_form.label :location, "Current Location"
  = location_form.text_field :location

#Application Helper
#nested attributes for user and location
def setup_user(user)
  returning(user) do |u|
    u.build_current_location if u.current_location.nil?
  end
end

#in the user controller (added after edit)
def update
    @user = @current_user
    if @user.update_attributes(params[:user])
      flash[:notice] = "Account updated!"
      redirect_to account_url
    else
      render :action => :edit
    end
  end
È stato utile?

Soluzione

Il problema esatto che stai affrontando, come altri hanno fatto notare è che il controller non riceve la posizione id come dovrebbe. Sembra a me l'id posizione viene fatto passare attraverso il parametro errato. Purtroppo una posizione id non esiste un nuovo record, quindi questo non è possibile in forma.

Il problema nasce dal accepts_nested_attributes_for uso su un rapporto belongs_to. Il comportamento non è chiaramente definito. Questo sembra essere un problema documentato. Così l'accepts_nested_attributes_for dovrebbe essere su un ha una o ha molti lato di una relazione.

Ecco alcune soluzioni possibili:

  1. Sposta l'accepted_nested_attributes_for al modello posizione e costruire i moduli viceversa.

    -form_for @location do |location_form|
     ...
     =location_form.fields_for @user do |user_form|
       ....
    

    Purtroppo questo non consente un modo logico di presentare le informazioni. E rende la modifica del diritto utente difficile.

  2. Utilizzare un modello di unirsi, e fare una ha uno:. Attraverso la relazione

    Io non sono onestamente sicuro come accept_nested_attributes_for funziona con: attraverso la relazione, ma sarà sicuramente risolvere il tuo problema con il collegamento record

  3. .
  4. Ignora accepts_nested_attributes_for e gestire l'associazione nel controller alla vecchia maniera.

    In realtà il mantenere accepts_nested_attributes_for. Esso fornisce alcuni metodi di convenienza a portata di mano, basta non lasciarlo arrivare alle update_attributes / creare comunicato.

    def update 
      @user = @current_user 
      completed = false
      location_params = params[:user].delete(:current_location_attributes)
    
      User.transaction do
        @location = Location.find_or_create_by_id(location_params)
        @user.update_attributes(params[:user]) 
        @user.current_location = @location
        @user.save!
        completed = true
      end
      if completed
        flash[:notice] = "Account updated!" redirect_to account_url 
      else 
        render :action => :edit 
      end
    end
    

I campi per popoleranno un campo ID nel current_location_attributes hash automaticamente, se non è la creazione di una nuova posizione. Tuttavia, find_or_create_by_id, richiede un: ingresso id nella hash per farlo funzionare. Si creerà un modo corretto di auto incrementato id se l'ID non è presente nel database. Se si sta creando una nuova posizione è necessario aggiungerlo. Più semplice per aggiungere al modulo con =location_form.hidden_field :id, 0 unless current\_location.new\_record?.

Tuttavia, si potrebbe desiderare di ridurre la creazione di posizione duplicato, e cambiare la linea Location.find_or_create_by_id a Location.find_or_create_by_location. Questo sarà anche ridurre eventuali errori di validazione unicità falliti.

Altri suggerimenti

Non fornire l'ID dell'attributo nidificato. Così rotaie pensa che sia una nuova.

- form_edit.fields_for :current_location do |location_form|
    = location_form.label :location, "Current Location"
    = location_form.text_field :location
    = location_form.hidden_field :id unless location_form.new_record?

Non so se la risposta precedente è propriamente corretto. Quello che vi serve è quello di specificare l'ID dell'utente per la posizione, non la posizione in sé.

- form_edit.fields_for :current_location do |location_form|
  = location_form.label :location, "Current Location"
  = location_form.text_field :location
  = location_form.hidden_field :user_id

Per impostazione predefinita belongs_to :current_location, :class_name => 'Location' si aspettano tavolo Users hanno un campo current_location_id. Una volta che hai questo si dovrebbe essere in grado di fare qualcosa di simile:

@user = @current_user
@user.update_attributes(params[:user])

@location = @user.current_location or @user.build_current_location
@location.update_attributes(params[:location]) 

@user.current_location.save!
@user.save!
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top