2016-02-12 25 views
5

Bir Rails kitaplığı uygulaması oluşturuyorum, bir tür has_many kitap ve bir kitap belongs_to tek bir tür. Form nesnesini kullanmam gerekiyor çünkü veri modelim sonuçta birden fazla çok ilişki var ve form nesnelerini nasıl kullanacağımı öğrenmek istiyorum. Form nesnesini Rails Cast # 416 Form Nesneleri'ni temel aldım. Formum, form nesnesi, modeller ve denetleyicimin hepsi çalışıyor gibi görünüyor. Yeni kitaplar yaratılır ve bunlar türlerle ilişkilendirilir, ama hepsi "tür" türündedir. find_or_create_by kullanıyorum. Bence sorun,'un içinde @genre ||= Genre.find_by(name: :name)'un aslında Tarz bilgisinden formdan geçmediğini düşünüyorum. aşağıdaki gibi Benim alakalı kodudur:Rails kullanma find_or_create_by form nesnelerle

Modeli book.rb

class Book < ActiveRecord::Base 
    belongs_to :genre 
    before_save :convert_isbn 
. 
. 
. 
end 

Modeli genre.rb

class Genre < ActiveRecord::Base 
    has_many :books, dependent: :destroy 
    validates_associated :books 
end 

book_form.rb

class BookForm 
    include ActiveModel::Model 

    def self.model_name 
    ActiveModel::Name.new(self, nil, "Book") 
    end 
. 
. 
. 
    validates :name, presence: true 

    delegate :name, to: :genre 
    delegate :title, :year, :pages, :isbn, :summary, :volume_a, :volume_b, to: :book 

    def genre 
    @genre ||= Genre.find_by(name: :name) 
    end 

    def book 
    @book ||= genre.books.build 
    end 

    def submit(params) 
    genre.attributes = params.slice(:name).permit(:name) 
    book.attributes = params.slice(:title, :year, :pages, :isbn, :summary, :volume_a,:volume_b).permit(:title, :year, :pages, :isbn, :summary, :volume_a,:volume_b) 
    if valid? 
     genre.save! 
     book.save! 
     true 
    else 
     false 
    end 
    end 
end 

books_controller.rb

class BooksController < ApplicationController 
    before_action :admin_user, only: [:new, :edit, :destroy] 

    def new 
    @book_form = BookForm.new 
    @genres = Genre.all 
    end 

    def create 
    @book_form = BookForm.new 
    @genres = Genre.all 
    if @book_form.submit(params[:book]) 
     flash[:success] = "You've added a new book to the library!" 
     redirect_to @book_form 
    else 
     render 'new' 
    end 
    end 
Avuç mücevher kullanma

Görünüm new.html.erb

<%= form_for @book_form do |f| %> 
    <%=render 'shared/error_messages', object: f.object %> 

    <%= f.label :title %> 
    <%= f.text_field :title, class: 'form-control' %> 
    . 
    . 
    . 
    <%= f.label :genre %><br> 

    <%= collection_select(:genre, :name, Genre.all, :name, :name) %> 
    <br> 
    <br> 
    <%= f.submit "Add book to library", class: "btn btn-primary" %> 
<% end %> 

, bir kitap oluşturmaya sunucudan bu olsun:

Bu yüzden kitap tarz parametrelerinde geçirilen oluyor
Started POST "/books" for ::1 at 2016-02-22 14:19:20 -0700 
Processing by BooksController#create as HTML 
    Parameters: {"utf8"=>"✓",  "authenticity_token"=>"bPusgyl9n+p07eQsEAe9CpSsithtkg33HMifj8KTsidv3GDLuhjibOC7d2mm5boC4w7ZUne64R4n4OMQotDE4g==", 
       "book"=>{"title"=>"test", 
       "year"=>"2016", 
       "pages"=>"222", 
       "isbn"=>"9780-xx-xx-xx", 
       "summary"=>"fake summary", 
       "volume_a"=>"1", 
       "volume_b"=>"2"}, 
       "genre"=>{"name"=>"Mystery"}, 
       "commit"=>"Add book to library"} 

From: /home/nathaniel/rails_apps/allredlib/app/forms/book_form.rb @ line 38 BookForm#submit: 

    37: def submit(params) 
=> 38: binding.pry 
    39: genre.attributes = params.slice(:name).permit(:name) 
    40: book.attributes = params.slice(:title, :year, :pages, :isbn, :summary, :volume_a,:volume_b).permit(:title, :year, :pages, :isbn, :summary, :volume_a,:volume_b) 
    41: if valid? 
    42:  genre.save! 
    43:  book.save! 
    44:  true 
    45: else 
    46:  false 
    47: end 
    48: end 

ama Kitap formumda yanlış yoldan erişiyorum. binding.pry'u açıklarsam, form, yapmak istediğim gibi "Gizem" türünün yerine "ad" türüyle yeni bir kitap oluşturur.

binding.pry kullanırken ben raylar içine @genre yazdığınızda, ben

[1] pry(#<BookForm>)> @genre 
=> #<Genre:0x007f19554e1220 
id: 20, 
name: "name", 
book_id: nil, 
created_at: Thu, 25 Feb 2016 20:28:45 UTC +00:00, 
updated_at: Thu, 25 Feb 2016 20:28:45 UTC +00:00> 

son binding.pry sonuçları almak 27: def tarz => 28: binding.pry 29: @genre || = Genre.find_or_initialize_by (ismi: ad) 30: # @ türü || = Genre.find_or_initialize_by (ad: parametreler [: türü] [: ad]) 31: uç

+1

Sanırım bunu arıyor olabilirsiniz? http://stackoverflow.com/questions/7537180/how-to-pass-argument-to-delegate-method-in-rails – lacostenycoder

+0

Evet, öyle düşünüyorum. Rails için oldukça yeni ve çözümlerini doğru şekilde nasıl uygulayacağımı bilmiyorum. Herhangi bir işaretçi? – neallred

cevap

3

Eğer Tarza göre ismine bakacak olursanız, metodun ismindeki nitelikten geçmeniz gerekir. seçenekler karma.

def genre 
    @genre ||= Genre.find_or_create_by(name: :name) 
end 

GÜNCELLEME

genre.attributes = { :name => params[:genre][:name] } 

-e doğru

değişiklik

genre.attributes = params.slice(:name).permit(:name) 

Ayrıca önce ve genre.save sonra binding.pry atmak! @genre yazıp ne yazdığınızı görün, çünkü türün metodu, bu karma değişkeni sadece ile göndererek bu karma değeri kabul eden örnek değişkenini yaratmış olmalı.

Aynı şeyi kitap paramları üzerinde düşünürdüm ama dilim iyi çalışıyorsa. Eğer form görünümünde Genre.all diyoruz çünkü Ayrıca

, muhtemelen denetleyici eylemleri bunu gerekmez, ancak bunu yaparsanız, o zaman çünkü yerine form görünümü collection_select içindeki nesneyi @genres kullanmayı düşünün Tüm talebi iki kez modele yüklüyoruz.

@genres = Genre.all 
+0

Bu çok faydalıdır. Cevabımın alt kısmındaki çıktıyı Pry'den ekledim. Doğru Tarz, en azından karma'ya geçmiştir, bu yüzden isim gibi görünmektedir: name = from = @genre || = Genre.find_or_create_by (name:: name) 'tür ismine erişmek için yanlış yoldur. Bir hataya neden olan veya sunucuyu çökerten @ genre.name veya genre.name kullanarak erişemiyorum. Test etmem gerektiğine katılıyorum ama henüz test yapmak için test etmem konusunda yeterli bilgi yok. – neallred

+0

Buna bir bakacağım. – lacostenycoder

+0

O 'Parametreler şöyledir: { "utf8"=> "✓", "authenticity_token"=> "bPusgyl9n + p07eQsEAe9CpSsithtkg33HMifj8KTsidv3GDLuhjibOC7d2mm5boC4w7ZUne64R4n4OMQotDE4g ==", "kitap"=> { "title"=> "test", "yıl"= > "2016", "pages" => "222", "isbn" => "9780-xx-xx-xx", "özet" => "sahte özet", "volume_a" => "1 ", " volume_b "=>" 2 "}, " tür "=> {" name "=>" Gizem "}, " commit "=>" Kitaplığa kitap ekle "}' ' – neallred

0

türe sahip tür oluştururken her seferinde tür olarak ayarlanır. Bir Tür'ü create istemezsiniz, muhtemelen sadece bir Tür'ü (new ile) örneklendirmek istersiniz. Ayrıca, bu

@genre ||= Genre.new 

gibi bir şey bu

@genre ||= Genre.find_or_create_by(genre: :genre) 

değişen

deneyin, başka "isim" gibi bir şeye modeli Türe üzerine alan "genre" adlandırma öneririz. Aksi halde, işler gerçekten kafa karıştırıcı olur.

collection_select(:genre, :genre, Genre.all, :genre, :genre) 

ve sanki "isim" değiştirmek için:

collection_select(:genre, :id, Genre.all, :genre, :genre) 

daha gibi olmalıdır:

Ben bu satırı düşünmek

collection_select(:genre, :name, Genre.all, :name, :name) 
+0

Bu doğru. @genre || = Genre.new ile ilgili problem türümü bulamayacak veya oluşturamayacak olmasıdır. Sadece nil olarak nitelik türüne sahip yeni bir tür oluşturur ve bir sonraki kimlik numarası olarak genre_id özelliğini kullanır. – neallred

+0

Bazı daha fazla yorum ekledim. Find_or_create ile kullandığınız problem, ilk kez "tür" türünü yaratacağı, daha sonra her seferinde aynı Tür'ü bulacağı ve yenilerini oluşturmayacağınızdır. Yoksa sadece eskilerin adını değiştireceksin. – msergeant

+0

Yardımlarınız için teşekkür ederiz. Türün kafa karıştırıcı bir sütun adı olduğunu kabul ettim ve değiştirdim. Gerçekten yapmak istediğim, zaten var olan bir türü seçmek ve onunla yeni bir kitap ilişkilendirmektir. Bunu statik olarak @genre || = Genre.find_by (ad:: Geçmiş) sonu ile tanımlayabilirim ama şunu değiştirmem gerekiyor: Geçmişi, form giriş değerini okuyan bir şeyle. Herhangi bir fikir? – neallred

İlgili konular