0

I have the following setup in rails:

book.rb can have many schools with a has_and_belongs-to_many :schools

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 can have many books with 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

In my db schema I have the pivot/join table for it and it looks as follows:

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

This works fine, i can add many schools to books and add the same book to another school. Thats great and works fine but I am trying to do the following with this model.

I am trying to stop a new school being created if that name already exists in the records but then still associate that record on the book as a relationship and add that to the book and pass it through.

So far i have tried in book.rb file this:

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

This did not add a school at all in the system.

I have also tried this in book.rb:

before_save :get_school

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

This threw these errors: ERROR: invalid input syntax for type boolean: "id"

I am struggling to see where this will begin and how to get it up and running.

M dunbavan
  • 1,157
  • 5
  • 22
  • 57
  • The `invalid input syntax` error you are getting is because your `where` call is incorrect. You can do `School.where(id: school.id)`. Does it then work as you expect? – ptd Oct 09 '14 at 16:56
  • no it still creates the duplicate record as I need to use ` School.where(school_name: school.school_name).first_or_create` and even with id it still duplicates the record in /schools index – M dunbavan Oct 09 '14 at 17:04
  • What about `if existing_school = School.where(school_name: school.school_name).first then school.id = existing_school.id end`. That would be inside the `self.schools.map` block. – ptd Oct 09 '14 at 17:09
  • Should that go inside the `self.schools.map do |school|` – M dunbavan Oct 09 '14 at 17:10
  • I get this error: `ERROR: duplicate key value violates unique constraint "schools_pkey" DETAIL: Key (id)=(43) already exists.` – M dunbavan Oct 09 '14 at 17:15

1 Answers1

1

So it seems like the issue you are having is that you are trying to accept_nested_attributes for items that already exist. I believe you want to reject nested attributes for schools that exist and instead just add the school to the book.

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

And then define find_school in your Book model.

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

This will not accept nested attributes for existing schools and instead just add the existing school to your Book.

ptd
  • 3,024
  • 16
  • 29
  • That still creates the duplicate school in the schools index – M dunbavan Oct 09 '14 at 18:15
  • Sorry, I had true and false mixed up, so it was only saving ones that exist. I edited the answer. – ptd Oct 09 '14 at 18:17
  • So, that answered your question? – ptd Oct 09 '14 at 18:27
  • Hey ptd: quick update, this works but for some reason does not render new fields say if I delete all nested records from that edit page and save then go back to the edit form it shows blank with no add school fields. Is this because of the above you think? – M dunbavan Oct 10 '14 at 10:46
  • Are you building any schools before rendering the form? The edit form will only show as many sets of fields as the `Book` has schools. You could do something like: `3.times { @book.schools.new }` before rendering the form. – ptd Oct 10 '14 at 14:45
  • Yes there are other schools in the backend already loaded. The only new schools should be added to that book – M dunbavan Oct 10 '14 at 15:17