Rails nested model forms: validate presence of foreign key unless user creates new record
In have a pretty simple rails app, here's my code:
class Post < ActiveRecord::Base
belongs_to :category
attr_accessible :category_id, :category_attributes
accepts_nested_attributes_for :category, :reject_if => :all_blank
end
class Category < ActiveRecord::Base
has_many :posts
end
#app/views/posts/_form.html.haml
= simple_form_for(@post) do |f|
= f.association :category
= f.simple_fields_for :category do |cat_f|
= cat_f.input :name
So when creating a new post, I have the option to choose a category (from the select menu) or create a new one (if it doesn't exist).
I want to validate that category_id is present, unless the user opts to create a new category
I'm guessing there's some kind of rails way to solve this problem - I know that I can't just add validates :category_id, :presence => true
as this will cause form submission to fail when the user decides to create a new category (and doesn't select one from the drop-down).
Second Question: I recently read a useful rails tutorial that showed you how to toggle between displaying the category select menu and the new category fields so that only one of the tw开发者_如何学Pythono is present on screen at any given time. Anyone got a link to something like that?
I think I have fixed this by replacing:
validates :category_id, :presence => true
with
validates :category, :presence => true
It seems to work. Strange one.
PS
I can only imagine that this works because :category
is considered present if the user selects something from the drop-down list OR if they create a new category using the nested form, whereas previously, with my original code, :category_id was only considered present when the user selected something from the drop-down and NOT when they created a new record.
In your PostsController, you probably want to check the incoming parameters in your create action to see if category_id is your default value (here, -1), and if so, create a new category from the text field. Something like this:
def create
if params[:post][:category_id] != -1
category = Category.create params[:post][:category_name]
# make sure category is attached to post
end
# rest of your create action
end
And something similar in your update action.
As for your second question, that's probably less Rails and better handled by Javascript. You could pretty easily have a radio button for 'use existing category' or 'create new category', and then use javascript to swap the DOM objects appropriately.
精彩评论