Domanda

Ho sviluppato menu a discesa di selezione stato-paese contingente e vorrei fattorizzare questo comportamento in un modello di indirizzo in modo da non dover copiare il comportamento dinamico (più o meno suddiviso tra vista e controller) ciascuno e ogni volta che voglio che l'utente sia in grado di inserire un indirizzo completo.

Fondamentalmente sto cercando di immergere le dita dei piedi un po 'più a fondo in SECCO. Ma non sono sicuro esattamente dove incorporare i comportamenti. Uso il modello o l'helper per creare i moduli necessari? Ancora più importante: dove e come posso invocare il comportamento dinamico per l'aggiornamento di elenchi di stati? Ho bisogno di un controller di indirizzo o potrebbe essere fatto tutto all'interno del modello?

In altre parole, quello che ho ora nella vista è qualcosa di simile:

  # _refine.html.erb
      <tr>
        <td>
        <%= label_tag :dest_country, 'Country: ' %></td><td>
          <%= select_tag :dest_country, 
            options_for_select(Carmen::country_names 
                      << 'Select a country', 
                :selected => 'Select a country'), 
            {:include_blank => true,
            :id => 'country_select',                              
            :style => 'width: 180px',
            :onchange => remote_function(
              :url => {:action => 'update_state_select'},
              :with => "'country='+value")} %>
        </td>      
      </tr>
      <tr>
          <div id="state_select_div">
            <td><%= label_tag :dest_state, 'State: &nbsp&nbsp' %></td>
            <td><%= select_tag :dest_state, 
                        options_for_select(Carmen::states('US').collect{
                                |s| [s[0],s[0]]} << ['Select a state'], 
                                :selected => 'Select a state'), 
                                {:style => 'width: 180px'} %></td>
          </div>      
      </tr>

Il metodo di aggiornamento è nel controller:

# search_controller.rb

def update_state_select
  # puts "Attempting to update states"
  states = []
  q = Carmen::states(Carmen::country_code(params[:country]))
  states = q unless q.nil? 
  render :update do |page|
    page.replace_html("state_select_div",
    :partial => "state_select",
    :locals => {:states => states }
  )
 end
end

Infine, ho un parziale che viene inserito con i nomi propri o un campo di testo vuoto:

# _state_select.html.erb
<% unless states.empty? or states.nil? %>
      <%= label_tag :dest_state, 'Select a state'  %>
 <br/> <%= select_tag :dest_state, 
                     options_for_select(states.collect{|s| [s[0],s[0]]}  
                         << ['Select a state'], 
                       :selected => 'Select a state'), 
                       {:style => 'width: 180px'} %>
 <% else %>
   <%= label_tag :dest_state, 'Please enter state/province' %><br />
   <%= text_field_tag :dest_state %>
<% end %>

Ora, ciò che mi piacerebbe fare è poter associare un indirizzo attraverso il modello (diciamo, Person has_one: address) e all'interno del modulo per creare una nuova persona, essere in grado di usare qualcosa come

 <%= label_tag :name, 'What's your name?' %>
 <%= text_field_tag :name %>
 <%= label_tag :address, 'Where do you live?' %>
 <%= address_fields_tag :address %>

Che potrebbe generare gli opportuni menu a discesa, accoppiati dinamicamente insieme, i cui risultati sarebbero accessibili attraverso Person.address.country e Person.address.state.

Grazie in anticipo!

È stato utile?

Soluzione

Vorrei prima assicurarmi di aver capito bene il codice; quando un utente cambia la casella di selezione del Paese e la richiesta AJAX viene inviata al server, che quindi invia uno script che aggiorna la casella degli Stati con le voci corrette?

In tal caso, utilizzerei una strategia completamente diversa. Utilizzare un callback attivato quando si modifica dest_country . Consenti a questo callback di eseguire una richiesta AJAX GET per es. /countries/{COUNTRY}/states.json (o .xml). Ovviamente devi avere un percorso e un controller configurati per questo. Popolare dest_state con i valori restituiti.

UPDATE: Per quanto riguarda il factoring del codice dell'interfaccia utente, prova a utilizzare parziali e helper. http://guides.rubyonrails.org/layouts_and_rendering.html#using-partials

Altri suggerimenti

I dati appartengono ai modelli e la presentazione appartiene ai modelli (e agli helper). Detto questo, inizierei a separare i dati dalla presentazione e a rimuovere il codice inutile.

states.collect{|s| [s[0],s[0]]}

AFAIK, questa esecuzione non è richiesta. Puoi semplificarlo in

states.collect{|s| s[0]}

o

states.collect(&:first)

ma soprattutto, puoi fornire un metodo personalizzato nella tua classe Carmen per ottenere i dati nel formato corretto.

Anche il seguente codice potrebbe essere semplificato usando: prompt = > " Seleziona uno stato " in modo che non sia necessario né aggiungere un nuovo elemento dell'array, né selezionare manualmente l'elemento chiamato " Seleziona uno stato " ;.

options_for_select(Carmen::states('US').collect{
                                |s| [s[0],s[0]]} << ['Select a state'], 
                                :selected => 'Select a state'),

Infine, potresti voler incapsulare aiutanti complessi nell'oggetto per rendere più semplice il test con una suite Test :: Unit. Dai un'occhiata a questo screencast .

Parlando del controller, cambia

# puts "Attempting to update states"
states = []
q = Carmen::states(Carmen::country_code(params[:country]))
states = q unless q.nil? 

in

# puts "Attempting to update states"
states = Carmen::states(Carmen::country_code(params[:country])) || []

Assicurati di non chiamare due metodi quando puoi chiamarne solo uno. Cambia

<% unless states.empty? or states.nil? %>

in

<% unless states.blank? %>

Ho scritto un post sul blog usando Carmen e jQuery. Il codice è riutilizzabile perché vive in modo parziale nelle viste dei miei indirizzi. Lo uso con un tag fields_for " address " nel modulo. Puoi leggere l'intera voce qui: http://eric.lubow.org/2009/ruby/rails/country-state-select-using-carmen-and-jquery/ .

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top