在create上添加模型/数据库关联

时间:2014-05-16 02:45:30

标签: ruby-on-rails

我有一个名为Entry的模型,它有很多类别。我创建/编辑条目的页面包含每个类别的复选框。

当我编辑条目时,一切正常。当我创建Entry时,我得到@entry的错误:

:entry_categories=>["is invalid"]

我的想法是,rails无法创建entry_categories,因为它不知道条目的ID(它不应该,它还没有被分配id)

我觉得这是一件很常见的尝试。虽然我还没有找到答案。这里有代码垃圾邮件,必须有一些我缺少的东西,希望一些更有经验的眼睛能看到它。

entry.rb

class Entry < ActiveRecord::Base

  validates_presence_of :contents
  validates_presence_of :title

  has_many :entry_categories, dependent: :destroy
  has_many :categories, through: :entry_categories

  belongs_to :book
  validates_presence_of :book

end

entry_category.rb

class EntryCategory < ActiveRecord::Base

  belongs_to :entry
  belongs_to :category

  validates_presence_of :entry
  validates_presence_of :category

end

category.rb

class Category < ActiveRecord::Base
  validates_presence_of :name
  validates_uniqueness_of :name

  has_many :entry_categories, dependent: :destroy
  has_many :entries, through: :entry_categories

end

entries_controller.rb

class EntriesController < ApplicationController
    before_action :find_entry, only: [ :show, :edit, :update, :destroy ]
    before_action :find_book, only: [ :new, :create, :index ]
    before_action :authenticate_admin!, only: [:new, :create, :edit, :update, :destroy ]

    def new
        @entry = Entry.new
    end

    def create
        @entry  = @book.entries.new( entry_params )
        if @entry.save
            redirect_to entry_path( @entry ), notice: 'Entry Created'
        else
            render :new
        end
    end

    def show
        @categories = Category.joins( :entry_categories ).where( "entry_categories.entry_id = #{@entry.id} " ).select( "name, categories.id " )
        @category_class = @categories.first.name.downcase.gsub( / /, '_' ) if @categories.any?
    end

    def index
        @entries = @book ? @book.entries : Entry.all
    end

    def edit
    end

    def update
        if @entry.update( entry_params )
            redirect_to entry_path( @entry ), notice: 'Entry Updated'
        else
            render :edit
        end
    end

    def destroy
        @book = @entry.book
        @entry.destroy
        redirect_to book_path( @book ) , notice: 'Entry Destroyed'
    end

    protected
    def entry_params
        params.require(:entry).permit( :title, :contents, :year, :month, :day, category_ids: [] )
    end

    def find_entry
        @entry = Entry.find( params[:id] )
    end

    def find_book
        @book = Book.find( params[ :book_id ] )
    rescue
        @book = nil
    end

end

_form.html.erb

<%= form_for [ @book, @entry ] do | form | %>
    <%= content_tag :p, title %>
    <%= form.text_field :title, placeholder: 'Title', required: true %>
    <%= form.number_field :year, placeholder: 'Year' %>
    <%= form.number_field :month, placeholder: 'Month' %>
    <%= form.number_field :day, placeholder: 'Day'     %>
    <%= form.text_area :contents %>
    <fieldset>
    <legend>Categories</legend>
    <%= form.collection_check_boxes(:category_ids, Category.all, :id, :name ) %>
    </fieldset>
    <%= form.submit %>
<% end %>

再次,entry_categories在create方法中无效,在更新中它们没问题。它是相同的html文件。

在尝试保存EntryCategory之前,必须有某种方法告诉rails保存Entry吗?

感谢。

3 个答案:

答案 0 :(得分:1)

我设法通过从EntryCategory中获取验证来实现这一点:

class EntryCategory < ActiveRecord::Base

  belongs_to :entry
  belongs_to :category

  validates_presence_of :category

end

我对这个解决方案并不是特别高兴,并且仍然会欣赏其他想法。

答案 1 :(得分:0)

试试这个:

替换此代码:

<%= form.collection_check_boxes(:category_ids, Category.all, :id, :name ) %>

使用:

<% Category.all.order(name: :asc).each do |category| %>
 <div>
    <%= check_box_tag "entry[category_ids][]", category.id %>
    <%= category.name %>
</div>

您可以使用fieldset代替div

对其进行格式化

答案 2 :(得分:0)

我认为您可以使用以下任何一种方法:

您可以使用Active Record关联的autosave功能。这样,当您保存EntryCategory时,它也会自动保存Entry

class EntryCategory < ActiveRecord::Base

  belongs_to :entry , autosave: true
  #rest of the code
end

您还可以使用活跃记录的before_save回调。这样,无论何时保存EntryCategory,它都会先调用指定的方法,而不是继续保存。

class EntryCategory < ActiveRecord::Base

  before_save :save_associated_entries
  #rest of the code

  def save_associated_entries
    # code to save associated entries here
  end 
end