如何在关系上创建记录,如果已存在则忽略并保存到关联?

时间:2014-10-09 16:26:11

标签: ruby-on-rails ruby ruby-on-rails-4 model has-and-belongs-to-many

我在rails中有以下设置:

book.rb可以有很多学校有一个has_and_belongs-to_many:学校

class Book < ActiveRecord::Base

    before_save :get_school

    include PgSearch
    pg_search_scope :search, :against => [:title, :slug, :synopsis, :body],
    using: { tsearch:{ dictionary: "english" } }

    def self.text_search(query)
      if query.present?
        where("title @@ :q or synopsis @@ :q", q: query)
      else
        scoped
      end
    end

    has_attached_file :jacket_cover, :styles => { :medium => "300x300>", :thumb => "100x100>" }, :default_url => "/images/:style/missing.png"
    validates_attachment_content_type :jacket_cover, :content_type => /\Aimage\/.*\Z/

    validates :jacket_cover, :title, :slug, :synopsis, :body, :age, :publisher, presence: true
    validates_uniqueness_of :title

    extend FriendlyId
    friendly_id :title, use: [:slugged, :finders]

    belongs_to :author
    belongs_to :gallery
    has_many :stories
    has_many :images

    has_and_belongs_to_many :schools, join_table: "books_schools"

    accepts_nested_attributes_for :author
    accepts_nested_attributes_for :gallery, :allow_destroy => true
    accepts_nested_attributes_for :schools, :reject_if => :all_blank, :allow_destroy => true
    accepts_nested_attributes_for :images, :allow_destroy => true

    def get_school
        self.schools.map do |school|
            School.where(:id).first_or_create
        end
    end

    scope :available, ->{ where(available: true) }
    scope :unavailable, ->{ where(available: [nil, false]) }

end

school.rb可以有很多书有has_and_belongs-to_many:books

class School < ActiveRecord::Base
    has_and_belongs_to_many :books

    validates :school_name, :address, presence: true
    #validates_uniqueness_of :school_name
end

在我的db模式中,我有它的pivot / join表,它看起来如下:

create_table "books_schools", id: false, force: true do |t|
    t.integer "book_id",   null: false
    t.integer "school_id", null: false
  end

  add_index "books_schools", ["book_id", "school_id"], name: "index_books_schools_on_book_id_and_school_id", using: :btree
  add_index "books_schools", ["school_id", "book_id"], name: "index_books_schools_on_school_id_and_book_id", using: :btree

这很好用,我可以在书上添加许多学校,并将同一本书添加到另一所学校。这很好,工作正常,但我试图用这个模型做以下。

如果该名称已经存在于记录中,但我仍然试图停止创建一所新学校,但仍然将该记录作为一种关系与书籍相关联,并将其添加到书中并传递给它。

到目前为止,我已经在book.rb文件中尝试了这个:

def schools_attributes=(schools_attributes)
     schools_attributes.values.each do |school_attributes|
       if school_attributes[:id].nil? and school_attributes[:school_name].present?
         school = School.find_by_school_name(school_attributes[:school_name])
         if school.present?
           school_attributes[:id] = school.id
           self.schools << school
         end
       end
     end
     #assign_nested_attributes_for_collection_association(:schools, schools_attributes)
    end

这并没有在系统中添加任何学校。

我也在book.rb中试过这个:。

before_save :get_school

def get_school
        self.schools.map do |school|
            School.where(:id).first_or_create
        end
    end

这引发了以下错误:ERROR: invalid input syntax for type boolean: "id"

我正在努力查看这将从何处开始以及如何启动和运行。

1 个答案:

答案 0 :(得分:0)

因此,您遇到的问题似乎是您正在尝试对已存在的项目进行accept_nested_attributes。我相信你想要拒绝存在的学校的嵌套属性,而只是将学校添加到书中。

accepts_nested_attributes_for :schools, :reject_if => :find_school, :allow_destroy => true

然后在find_school模型中定义Book

def find_school(school)
  if existing_school = School.find_by_school_name(school['school_name'])
    self.schools << existing_school
    return true
  else
    return false
  end
end

这不会接受现有学校的嵌套属性,而只是将现有的学校添加到Book