2011-01-09 6 views
17

Su un modello di contenuto ha un attributo denominato slug. Quando creo un nuovo record, voglio usare un helper per popolare questo campo, ma su un record esistente voglio usare il valore dal database.Rails: valore predefinito in text_field ma solo per new_record?

Attualmente ho:

<% if @content.new_record? %> 
    <%= f.text_field :slug, :value => "#{generate_slug(6)}" %> 
<% else %> 
    <%= f.text_field :slug %> 
<% end %> 

Ma che sembra un po 'prolisso. È questo il modo migliore, o non c'è altro modo? (Rails newb solo cercando di trovare la "via Rails" sulle questioni io sono sicuro di)


Modifica

Vorrei sottolineare che l'aiuto è attualmente in/app/aiutanti/application_helper .rb Spostato per essere un'azione privata nel controller Contenuto. La risposta di David ha funzionato alla grande.

risposta

24

Nel vostro controller

@content.slug ||= generate_slug(6) 

Ciò assegnare un valore all'attributo slug se nessuno è presente

Quindi, a suo avviso si può semplicemente utilizzare

<%= f.text_field :slug %> 
+0

Questo sembra fantastico. Come posso rendere il mio aiuto accessibile all'interno del controller? (generate_slug (6) è un helper). Ricevo 'metodo non definito' generate_slug 'per # ' – jyoseph

+0

Scratch che, l'ho aggiunto come azione privata nel controller Contents. Non mi preoccupare! Grazie per la risposta! – jyoseph

+0

Come notato da carpeliam, a seconda di come e quanto spesso si utilizzerà questa funzionalità, si potrebbe voler inserire il modello come metodo ('def slug; | sl = generate_slug (6); end) . –

0

Opzioni

  1. Prova after_initialize callback nel tuo modello.
  2. Provare a creare un metodo nel modello in cui si impostano i valori predefiniti e chiamarlo nella nuova azione nel controller. Chiama anche questo metodo se la tua creazione fallisce e tu rendi nuovo. Ricordare di impostare il valore predefinito solo quando non esiste alcun valore utilizzando l'operatore | | =.

Esempio da seguire. Sto digitando sul telefono!

+1

'after_initialize' probabilmente non è la soluzione migliore, poiché verrà anche chiamato ogni volta che recuperi un oggetto dal db. A meno che non sia quello che vuoi? –

0

Mi capita di utilizzare jQuery nei miei progetti, quindi quando voglio alcune funzionalità come questa, di solito uso qualcosa come labelify. Quindi, userei qualcosa come <%= f.text_field :slug, :title => generate_slug(6) %>. (Suggerimento, non è necessario inserire la chiamata #generate_slug all'interno di una stringa se restituisce qualcosa che si risolve in una stringa da sola, anzi è più performante se non lo fai.)

Se si non voglio andare con l'approccio jQuery, potresti voler avvolgere questo pezzo di logica nel tuo modello.

def Content < ActiveRecord::Base 
    def slug 
    self.new_record? ? self.slug_for_new_record : attributes[:slug] 
    end 

    private 
    def slug_for_new_record 
    # I don't know what you're doing in generate_slug, but it sounds model- 
    # related, so if so, put it here and not in a helper 
    end 
end 

Se appartiene realmente nella vista, ancora un'altra opzione è quella di rendere il vostro proprio rubino un po 'più conciso (dovrete giudicare se questo è più leggibile):

<%= f.text_field :slug, :value => (generate_slug(6) if @content.new_record?) %> 

Non dimenticare i parenti che circondano lo (generate_slug(6) if @content.new_record?). Se lo fai, lo if verrà applicato a text_field, che non è quello che desideri.

Ma ci sono ancora altri modi per farlo. La riga di codice sopra non è eccezionale se la tua logica potrebbe cambiare e stai incollando questo codice su tutto il tuo progetto di rotaie.Quando volevo aggiungere una classe 'required' ai miei campi di testo, ma solo se erano un nuovo record (avevamo alcuni dati legacy che non volevamo far pulire le persone), ho creato il mio builder con un required_field metodo che ha appena chiamato text_field e ha aggiunto una classe 'richiesta' se l'elemento era un nuovo record. Questo potrebbe sembrare un lavoro, ma abbiamo circa 20 diverse forme, ognuna con potenzialmente più campi obbligatori, ed è molto più facile cambiare la logica aziendale in un unico posto. Quindi, se pensi davvero che questa logica appartenga alla vista ma hai un sacco di queste righe di codice e non vuoi doverle modificare in un milione di posti, allora FormBuilder è la strada da percorrere. Penso che questo sia nella maggior parte dei casi più carino e più appropriato di un aiutante, ma, di nuovo, la bellezza è negli occhi di chi guarda. Ecco il mio codice di un po 'adattato per il vostro caso:

# config/environment.rb 
ActionView::Base.default_form_builder = NamespacesAreFun::FormBuilder 

# lib/namespaces_are_fun/form_builder.rb 
module NamespacesAreFun 
    class FormBuilder < ActionView::Helpers::FormBuilder 
    def slug_field(method, options = {}) 
     opts = options.to_options 
     opts.merge!(:value => generate_slug) if self.object.new_record? 
     text_field(method, opts) 
    end 
    end 
end 

# views/.../your_view.html.erb 
<%= f.slug_field :slug %> 

Speriamo che in tutti questi diversi approcci è uno che misura il vostro progetto.

+0

Non ho i privilegi per lasciare commenti sulla risposta di David, ma questo sembra un posto dove si potrebbe voler applicare "Fat Model Skinny Controller". http://weblog.jamisbuck.org/2006/10/18/skinny-controller-fat-model – carpeliam

+0

Ho commentato la mia risposta in tal senso. Anche se questo dovrebbe essere inserito nel modello solo se usato frequentemente. Se (ad es.) Viene utilizzato solo come attributo predefinito in un singolo luogo (ad esempio, l'utente sceglie una lumaca al momento dell'iscrizione, con un valore predefinito fornito per lui) dovrebbe entrare nel controller solo (solo) in quella specifica azione. –

Problemi correlati