mam następujący problem, chciałbym aby produkt miał wiele wariantów. Jeden z nich jest główny (master = true) i chciałbym go ustawiać podczas tworzenia/edytowania produktu, a dodawać kolejne normalnie w widoku wariantów dla danego produktu ( product/1/variants )
wariant składa się z pól product_id, master, price
.field
= f.label :price
%br/
= f.text_field :price
Kod wyżej w text_fieldzie zwraca cały obiekt wariantu a nie tylko cene. Przy edycji/tworzeniu produktu to się sypie.
Jak zrobić to w sensowny dla rubiego i railsów sposób?
Probowałem z :through ale nie wyszło…
No pewnie, że zwraca cały obiekt, dlatego, że przypisujesz mu cały obiekt w asocjacji. Możesz zrobić tak w modelu Product :
has_one :master, :class_name => 'Variant'
Potem będziesz mógł odwoływać sie do tego wariantu poprzez @product.master, np. @product.master.price
Natomiast w formularzu można wówczas zastosować zagnieżdżanie (Railscasty 196 i 197). Generalnie idea jest taka, że w formularzu tworzącym Product od razu utworzysz obiekt klasy Variant, który zostanie przypisany jako master tworzonego produktu.
Jeśli koniecznie chcesz odwoływać się bezpośrednio przez @product.price, to dodaj jakiś callback, który przy aktualizacji ustawi wartość zmiennej price produktu, na taką jak ma jego główny wariant. Osobiście zostałbym jednak przy pierwszej opcji, tzn. odwoływania się @product.master.price
Jeśli chcesz używać np. @product.price to http://apidock.com/rails/Module/delegate będzie jak znalazł. Czyli np.
delegate :price, :to => @master, :prefix => false
Nie wiem po co mi railscasty 196 i 197. Przy tworzeniu produktu tworzy sie wariant z master => nil. Przy edycji wyswietla mi wszystkie warianty przypisane do danego produktu! a ja chce jedynie master. tak działa fields_for.
W konsoli to dziala. Tylko jak zrobic to w widokach?
- f.fields_for :variants do |b|
.field
= b.label :price
%br/
= b.text_field :price
Dla tworzenia i edycji jest to samo jak na razie. Jest to wg railscastow 196 i 197.
:variants powoduje wywołanie metody @product.variants, pewnie dlatego masz wszystkie warianty przy edycji. Jeśli chcesz zawsze edytować tylko master, to możesz to zrobić na dwa sposoby:
w formularzu:
fields_for :master_variant do |variant|
variant.hidden_field :master, true
variant.text_field :price
w modelu Product:
1 metoda w ogole nie działa, ani przy tworzeniu ani przy edycji nie ma wariantu…
2 metoda przy edycji zwraca poprawnie wariant master, ale przy tworzeniu nie ma żadnego pola. w kontrolerze w akcji new probowalem dodac
def new
@product = Product.new
@product.master_variant.build
co daje bład:
undefined method `build’ for nil:NilClass
a chyba nic innego zrobic sie nie da? bo w akcji new nie bede przeciez tworzył juz obiektów.
f.fields_for :master_variant do |variant|
variant.hidden_field :master, true
.field
= variant.label :price
%br/
= variant.text_field :price[/code]
w kontrolerze
def new
@product = Product.new
@product.build_master_variant
a model
has_many :variants, :dependent => :destroy
has_one :master_variant, :class_name => 'Variant' , :conditions => {:master => true}
W widoku nie wyswietla sie pole Price, ani podczas tworzenia ani podczas edycji istniejacego produktu z wariantem master.
# products_controller.rb
def new
@product = Product.new
@product.build_master_variant
end
[code=ruby]- form_for @product do |f|
pola produktu
f.fields_for :master_variant, @product.master_variant do |variant|
= variant.hidden_field :master, :value => true
%p
= variant.label :price
= variant.text_field :price[/code]
Pisane w Ruby 1.8.7 i Rails 2.3.5, ale nie powinno się jakoś specjalnie różnić od Twojego setupu.
Dzieki wszystkim, w szczególności squilowi. Jednak nie działa to na railsach 3beta4 i ruby 1.9.2 , pewnie jest jakiś inny sposób… Jednak cofnę się do rubiego 1.8.7 i railsow 2.3.8
Rozwiązałem swój problem w rails3
[code]= form_for [:admin, @product] do |f|
= f.error_messages
.field
= f.label :name
%br/
= f.text_field :name
= f.fields_for :master_variant, @product.master_variant do |variant|
.field
= variant.hidden_field :master, :value => true
= variant.label :price
%br/
= variant.text_field :price[/code]
Czyli przed fields_for oraz form_for korzystamy z bloków <%= %>, a nie <% %> i teraz działa to na railsach 3beta4 i ruby 1.9.2