i'm trying to save two object (image and event) using one form (event form),
but the when i submit the button there is only event object that created, the images object not save to images table,
models/event.rb
has_one :images, :class_name => '::Refinery::Image'
accepts_nested_attributes_for :images, :allow_destroy => true
models/image.rb
belongs_to :events, class_name: 'Refinery::Events::Event'
events_controller.rb
def new
#event = Event.new
#event.build_images
end
def create
#event = Event.new(event_params)
end
def event_params
params.require(:event).permit(:nama, :deskripsi, images_attributes:[:id, :image_name, :image_size, :image_width, :image_height, :created_at, :updated_at, :image_mime_type, :image_uid, :image_title, :image_alt, :event_id] )
end
events/_form.html.erb
<%= form_for [refinery, :events, #event], :html => { :multipart => true } do |f| %>
<%= render '/refinery/admin/error_messages',
:object => #event,
:include_object_name => true %>
<div class='field nama_field string_field'>
<%= f.label :nama %>
<%= f.text_field :nama %>
</div>
<div class='field deskripsi_field text_field'>
<%= f.label :deskripsi %>
<%= f.text_area :deskripsi, :rows => 8 %>
</div>
<%= f.fields_for :images do |ff| %>
<div>
<%= ff.label :images %>
<%= ff.file_field :images %>
</div>
<% end %>
<div class='actions'>
<%= f.submit t('.send') %>
</div>
<% end %>
anyone can help me why the images not saved into images table?
So this may be somewhat related to my question that I asked earlier, so here is a link to it, just in case.
So, currently I'm getting the error undefined method 'location' for #<Block:0x6503478>.
I've already gotten the has_one relation for cue working, but what seems to be the problem is the has_many relations with block_block and block_character.
The parameters being passed are:
{"utf8"=>"✓",
"authenticity_token"=>"blahblahblah",
"block"=>{"block_code"=>"1",
"block_duration"=>"",
"cue"=>"no",
"cue_attributes"=>{"cue_code"=>"",
"cue_type_code"=>"",
"cue_description"=>"",
"cue_method_code"=>""},
"location_code"=>"1",
"scene_code"=>"1",
"block_description"=>"",
"block_block"=>{"block_block_code"=>"",
"primary_block_code"=>"",
"secondary_block_code"=>"",
"block_block_start"=>""},
"block_character"=>{"block_character_code"=>"",
"character_code"=>"",
"block_code"=>"",
"character_action"=>"",
"character_motivation"=>""}},
"blockblock"=>{"block"=>"no"},
"blockblockdirect"=>{"blockdirect"=>"before"},
"blockchar"=>{"character"=>"no"},
"commit"=>"Create Block"}
Here is my form for block (views/block/_form.html.erb):
<%= form_for(#block) do |f| %>
<% if #block.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#block.errors.count, "error") %> prohibited this block from being saved:</h2>
<ul>
<% #block.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field hidden">
<%= f.label :block_code, class: "hidden" %><br>
<%= f.text_field :block_code, class: "form-control hidden" %>
</div>
<div class="field">
<%= f.label :block_duration %><br>
<div class="input-group">
<%= f.number_field :block_duration, class: 'text_field form-control', :step => 'any' %>
<div class="input-group-addon">seconds</div>
</div>
</div>
<div class="field">
<%= label "cue", "Does this block have a cue associated with it?" %>
<!-- Add whether it is specific/generic cue -->
<%= radio_button_tag "block[cue]", "yes", false %> Yes
<%= radio_button_tag "block[cue]", "no", true %> No
<div class="field" id="cue_fields" style="display:none;">
<%= f.fields_for :cue, #block.build_cue do |ff| %>
<div class="field hidden">
<%= ff.label :cue_code, class: "hidden" %><br>
<%= ff.text_field :cue_code, class: "hidden" %>
</div>
<div class="field">
<%= ff.label "Cue Type" %><br>
<%= ff.collection_select(:cue_type_code, CueType.all, :cue_type_code, :cue_type_name, {prompt: "Select a cue type..."}, {class: "form-control"}) %>
</div>
<div class="field">
<%= ff.label "Cue Description" %><br>
<%= ff.text_area :cue_description, class: "form-control" %>
</div>
<div class="field">
<%= ff.label "Cue Method" %><br>
<%= ff.collection_select( :cue_method_code, CueMethod.all, :cue_method_code, :cue_method_name, {prompt: "Select a cue method..."}, {class: "form-control"}) %>
</div>
<% end %>
</div>
</div>
<div class="field">
<%= f.label "Location" %><br>
<%= collection_select :block, :location_code, Location.all, :location_code, :location_name, {prompt: "Select a location..."}, {class: "form-control", required: true} %>
</div>
<div class="field">
<%= f.label "Scene" %><br>
<%= f.collection_select :scene_code, Scene.all, :scene_code, :actAndScene, {prompt: "Select a scene..."}, {class: "form-control", required: true} %>
</div>
<div class="field">
<%= f.label "Block Description" %><br>
<%= f.text_area :block_description, class: "form-control" %>
</div>
<!-- This needs work -->
<div class="field">
<%= label "blockblock", "Is this block associated with any other blocks?" %>
<%= radio_button_tag "blockblock[block]", "yes", false %> Yes
<%= radio_button_tag "blockblock[block]", "no", true %> No
<div class="field" id="blockblock_fields" style="display:none;">
<ol>
<li>
<%= label "blockdirect", "Does this block come directly before or after another block?" %>
<%= radio_button_tag "blockblockdirect[blockdirect]", "before", true %> Before
<%= radio_button_tag "blockblockdirect[blockdirect]", "after", false %> After
<%= f.fields_for :block_block do |gg| %>
<div class="field hidden">
<%= gg.label :block_block_code, class: 'hidden' %><br>
<%= gg.text_field :block_block_code, class: 'hidden' %>
</div>
<div class="field" id="blockblock_after_fields" style="display:none;">
<%= gg.label "Primary Block Code" %><br>
<%= gg.text_field :primary_block_code, class: 'form-control' %>
</div>
<div class="field" id="blockblock_before_fields">
<%= gg.label "Secondary Block Code" %><br>
<%= gg.text_field :secondary_block_code, class: 'form-control' %>
</div>
<div class="field">
<%= gg.label "Block Start" %><br>
<p><i>This field indicates the amount of time after the first block starts that the second block should begin, i.e. if you type "1" here, then the second block will start 1 second after the first block starts</i></p>
<div class="input-group">
<%= gg.number_field :block_block_start, class: 'text_field form-control', :step => 'any' %>
<div class="input-group-addon">seconds</div>
</div>
</div>
<% end %>
</li>
</ol>
</div>
</div>
<!-- This needs work -->
<div class="field">
<%= label "character", "Are any characters associated with this block?" %>
<%= radio_button_tag "blockchar[character]", "yes", false %> Yes
<%= radio_button_tag "blockchar[character]", "no", true %> No
<div class="field" id="character_fields" style="display:none;">
<ol>
<%= f.fields_for :block_character do |hh| %>
<li>
<div class="field hidden">
<%= hh.label :block_character_code, class: 'hidden' %><br>
<%= hh.text_field :block_character_code, class: 'hidden' %>
</div>
<div class="field">
<%= hh.label "Character" %><br>
<%= hh.collection_select :character_code, Character.all, :character_code, :character_name, {prompt: "Select a character..."}, {class: "form-control"} %>
</div>
<div class="field hidden">
<%= hh.label :block_code, class: 'hidden' %><br>
<%= hh.text_field :block_code, class: 'hidden' %>
</div>
<div class="field">
<%= hh.label :character_action %><br>
<%= hh.text_field :character_action, class: 'form-control' %>
</div>
<div class="field">
<%= hh.label :character_motivation %><br>
<%= hh.text_area :character_motivation, class: 'form-control' %>
</div>
</li>
<% end %>
</ol>
</div>
</div>
<div class="actions">
<%= f.submit "Create Block", class: "btn btn-primary" %>
</div>
<% end %>
Additionally, here are the models associated with block, block_character, and block_block, respectively:
class Block < ActiveRecord::Base
validates_presence_of :location
validates_presence_of :scene
has_one :cue
has_many :block_blocks
has_many :block_characters
accepts_nested_attributes_for :cue, allow_destroy: true
accepts_nested_attributes_for :block_blocks, allow_destroy: true
accepts_nested_attributes_for :block_characters, allow_destroy: true
attr_accessor :block_blocks
attr_accessor :block_characters
end
class BlockBlock < ActiveRecord::Base
belongs_to :block
end
class BlockCharacter < ActiveRecord::Base
belongs_to :block
end
Here is the controller for block:
class BlocksController < ApplicationController
before_action :set_block, only: [:show, :edit, :update, :destroy]
# GET /blocks
# GET /blocks.json
def index
#blocks = Block.all
end
# GET /blocks/1
# GET /blocks/1.json
def show
end
# GET /blocks/new
def new
#block = Block.new
# Set block code as next integer after max block code.
#block.block_code = (Block.maximum(:block_code).to_i.next).to_s(2)
end
# GET /blocks/1/edit
def edit
end
# POST /blocks
# POST /blocks.json
def create
#block = Block.new(block_params)
respond_to do |format|
if #block.save
format.html { redirect_to #block, notice: 'Block was successfully created.' }
format.json { render :show, status: :created, location: #block }
else
format.html { render :new }
format.json { render json: #block.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /blocks/1
# PATCH/PUT /blocks/1.json
def update
respond_to do |format|
if #block.update(block_params)
format.html { redirect_to #block, notice: 'Block was successfully updated.' }
format.json { render :show, status: :ok, location: #block }
else
format.html { render :edit }
format.json { render json: #block.errors, status: :unprocessable_entity }
end
end
end
# DELETE /blocks/1
# DELETE /blocks/1.json
def destroy
#block.destroy
respond_to do |format|
format.html { redirect_to blocks_url, notice: 'Block was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_block
#block = Block.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def block_params
params.require(:block).permit(:block_code, :block_duration, :cue_code, :location_code, :scene_code, :block_description, :cue_attributes => [:id, :cue_code, :cue_type_code, :cue_description, :cue_method_code], :block_block_attributes => [:id, :block_block_code, :primary_block_code, :secondary_block_code, :block_block_start], :block_character_attributes => [:id, :block_character_code, :character_code, :block_code, :character_action, :character_motivation])
end
end
And finally, the migrations I added for id and foreign_key for both block_block and block_character:
class AddBelongsToToBlockBlocks < ActiveRecord::Migration
def change
add_reference :block_blocks, :block, index: true
add_foreign_key :block_blocks, :blocks
end
end
class AddBelongsToToBlockCharacters < ActiveRecord::Migration
def change
add_reference :block_characters, :block, index: true
add_foreign_key :block_characters, :blocks
end
end
Honestly, thank you all so much for your help through this, I am by no means an advanced Rails user and this has all been amazingly helpful. Please let me know if you need any more information!
UPDATE 1
So I changed the following in block.rb (the model file), as suggested by Vijay (thanks so much!!!):
class Block < ActiveRecord::Base
validates_presence_of :location_code
validates_presence_of :scene_code
has_one :cue
has_many :block_blocks
has_many :block_characters
accepts_nested_attributes_for :cue, allow_destroy: true
accepts_nested_attributes_for :block_blocks, allow_destroy: true
accepts_nested_attributes_for :block_characters, allow_destroy: true
attr_accessor :block_blocks
attr_accessor :block_characters
end
At this point, the block saves (and appears in the index view), but the block_block and block_character do not do so. There is no associated error however...
UPDATE 2
This is currently what the params submitted look like:
Which is odd because it says that cue, block_block, and block_character are unpermitted parameters, even though, in the controller they are:
def block_params
params.require(:block).permit(:block_code, :block_duration, :cue_code, :location_code, :scene_code, :block_description, :cue_attributes => [:id, :cue_code, :cue_type_code, :cue_description, :cue_method_code], :block_block_attributes => [:id, :block_block_code, :primary_block_code, :secondary_block_code, :block_block_start], :block_character_attributes => [:id, :block_character_code, :character_code, :block_code, :character_action, :character_motivation])
end
Are you triggering the error in the validation?
validates_presence_of :location
From your code it looks like it should be
validates_presence_of :location_code
Not sure why you've added these in Rails 4
attr_accessor :block_blocks
attr_accessor :block_characters
Try removing them and see if they are interfering with the controller (I'm guessing, but happy to play if you put up a jsfiddle)
I have scoured all the other questions relating to this topic here, but I am still having this problem. I have a nested form inside a nested form. Answer choices are inside questions which are inside survey. I had no problem setting up the questions, and they save fine. The Answer choices, though, are not saving, and I cannot figure out where I am going wrong.
survey.rb
class Survey < ActiveRecord::Base
belongs_to :author
has_many :questions, dependent: :destroy
has_many :forms, dependent: :destroy
has_many :answer_choices, through: :question
validates :name, uniqueness: true
accepts_nested_attributes_for :questions, reject_if: proc { |attributes| attributes['text'].blank?},
allow_destroy: true
end
question.rb
class Question < ActiveRecord::Base
belongs_to :survey
has_many :responses, dependent: :destroy
has_many :answer_choices, dependent: :destroy
accepts_nested_attributes_for :answer_choices, reject_if: proc { |attributes| attributes['content'].blank?},
allow_destroy: true
end
answer_choice.rb
class AnswerChoice < ActiveRecord::Base
belongs_to :question
end
survey_controller.rb
def new
#survey = Survey.new(author_id: session[:user_id])
#survey.questions.build
#survey.questions.each { |question| 4.times { question.answer_choices.build }}
end
def edit
#survey.questions.build
#survey.questions.each { |question| 4.times { question.answer_choices.build }}
end
def survey_params
params.require(:survey).permit(:name, :description, :author_id,
questions_attributes: [:id, :text, :required, :response_type,
:_destroy, :number])
end
_form.html.erb
<%= form_for(#survey) do |f| %>
<% if #survey.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#survey.errors.count, "error") %> prohibited this survey from being saved:</h2>
<ul>
<% #survey.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :description %><br>
<%= f.text_field :description %>
</div>
<div class="field">
<%= f.hidden_field :author_id %>
</div>
<h2>Questions</h2>
<%= f.fields_for(:questions) do |ff| %>
<%= render 'questions', :f => ff %>
<% end %>
<div class="actions">
<%= f.submit 'Submit Question'%>
</div>
<div class="actions">
<%= link_to 'Finish Survey', surveys_path %>
</div>
<% end %>
_questions.html.erb
<div>
<span><%= f.index + 1 %>. </span>
<div class="field">
<%= f.hidden_field :number, value: f.index + 1 %>
</div>
<div class="field">
<%= f.label :text, "Question" %><br>
<%= f.text_field :text %>
</div>
<div class="field">
<%= f.label :response_type %><br>
<%= f.select :response_type, [["Yes/No", "yes/no"], ["Short Answer", "string"], ["Long Answer", "text"], ["Multiple Choice", "multi"]] %>
</div>
<div class="field">
<%= f.label :required %>
<%= f.check_box :required %>
</div>
<div>
<p>Answer Choices</p>
<%= f.fields_for(:answer_choices) do |ff| %>
<%= render 'answer_choices', :f => ff %>
<% end %>
</div>
<div class="field">
<%= f.label :_destroy %>
<%= f.check_box :_destroy %>
</div>
</div>
_answer_choices.html.erb
<div class="field">
<%= f.label :content %><br>
<%= f.text_field :content %>
</div>
<div class="field">
<%= f.label :_destroy %>
<%= f.check_box :_destroy %>
</div>
A few changes in your code.
Change your new method like this
def new
#survey = Survey.new(author_id: session[:user_id])
#questions = #survey.questions.build
#answer_choices = 4.times { #questions.answer_choices.build }
end
Your survey_params should look like this
def survey_params
params.require(:survey).permit(:name, :description, :author_id,
questions_attributes: [:id, :text, :required, :response_type,
:_destroy, :number, answer_choices_attributes: [:id,:content,:_destroy]])
end
And in your form code, change these lines
<%= f.fields_for(:questions) do |ff| %>
<%= f.fields_for(:answer_choices) do |ff| %>
into
<%= f.fields_for #questions do |ff| %>
<%= f.fields_for #answer_choices do |ff| %>
according to http://guides.rubyonrails.org/getting_started.html, I have below relationship models,
class Tag < ActiveRecord::Base
belongs_to :post
attr_accessible :name
end
class Post < ActiveRecord::Base
attr_accessible :context, :title, :tags_attributes
validates :title, :presence => true
validates :context, :presence => true, :length => {:minimum => 5}
has_many :comments
has_many :tags
accepts_nested_attributes_for :tags, :allow_destroy => :true,
:reject_if => proc {|attrs| attrs.all? {|k,v| v.blank?} }
end
normally below code could work well when I sent a edit request,these existing tags are listed as editable elements on the page.
<%= form_for(#post) do |post_form| %>
<%= post_form.fields_for :tags do |tag_form|%>
<div class="field">
<%= tag_form.label :name, 'Tag:' %>
<%= tag_form.text_field :name %>
</div>
<% unless tag_form.object.nil? || tag_form.object.new_record? %>
<div class="field">
<%= tag_form.label :_destroy, 'Remove:' %>
<%= tag_form.check_box :_destroy %>
</div>
<% end %>
<% end %>
but now,refer to below instance code on http://guides.rubyonrails.org/form_helpers.html
<%= form_for #person, :url => { :action => "create" } do |person_form| %>
<%= person_form.text_field :name %>
<%= fields_for #person.contact_detail do |contact_details_form| %>
<%= contact_details_form.text_field :phone_number %>
<% end %>
<% end %>
then I change the statement with fields_for to below format, why it always always prompt
undefined method `model_name' for Array:Class
<%= fields_for #post.tags do |tag_form|%>
at last, I make it work with below update
<% #post.tags.each do |tag| %>
<%= post_form.fields_for tags,tag do |tag_form|%>
<div class="field">
<%= tag_form.label :name, 'Tag:' %>
<%= tag_form.text_field :name %>
</div>
<% unless tag_form.object.nil? || tag_form.object.new_record? %>
<div class="field">
<%= tag_form.label :_destroy, 'Remove:' %>
<%= tag_form.check_box :_destroy %>
</div>
<% end %>
<% end %>
<% end %>
I haven't had a problem with validations before but this time I am having issues with nested_form validations. I am using Twitter Bootstrap and can get flash errors to show with, say, this:
def create
#recipe = current_user.recipes.new(params[:recipe])
if #recipe.save
redirect_to my_recipes_path, :notice => "Thanks #{current_user.name} Recipe sucessfully created."
else
render :action => 'new'
end
end
For my flash messages I use this in my app/layouts
<% flash.each do |name, msg| %>
<div class="alert alert-<%= name == :notice ? "success" : "error" %>">
<a class="close" data-dismiss="alert">×</a>
<%= content_tag :div, msg, :id => "flash_#{name}" if msg.is_a?(String) %>
</div>
<% end %>
So I thought I would try and just get one of the validators working, so my model
class Recipe < ActiveRecord::Base
belongs_to :user
delegate :name, :to => :user, :prefix => :user, :allow_nil => true
belongs_to :country
has_many :ingredients
has_many :preperations
has_many :favourites
validates_presence_of :dish_name
and my form
<%= nested_form_for #recipe do |f| %>
<div class="field_with_errors">
<%= f.label :dish_name, "Dish Name" %>
<%= f.text_field :dish_name, :placeholder => "Enter Dish Name" %>
</div>
<%= f.label :country_id, "Country Of Origin" %>
<%= f.collection_select(:country_id, Country.all, :id, :name, :prompt => 'Please select country') %>
<%= f.label :category, "Category" %>
<%= f.select :category, [['Starter'], ['Main Course'], ['Desserts'], ['Vegeterian']], {:include_blank => 'Please Select'} %>
<%= f.label :difficulty, "Difficulty Level" %>
<%= f.select :difficulty, [['Beginner'],['Intermediate'],['Expert']], {:include_blank => 'Please Select'} %>
<%= f.label :preperation_time, "Preperation Time (Mins)" %>
<%= f.select :preperation_time, [['15-30 Mins'],['30-60 Mins'],['60-120 Mins']], {:include_blank => 'Please Select'} %>
<%= f.fields_for :ingredients do |ing| %>
Ingredient<br>
<%= ing.text_field :ingredient_name , :placeholder => "Enter Ingredient Here" %><br>
<% end %>
<%= f.link_to_add "Add an Ingredient", :ingredients %><br>
<%= f.fields_for :preperations do |prep| %>
Preperation Step<br>
<%= prep.text_field :prep_steps , :placeholder => "Enter step Here" %><br>
<% end %>
<%= f.link_to_add "Add a step", :preperations %><br>
<%= f.label :description, "Description of Recipe" %>
<%= f.text_area :description, :size=> "60x10" %></br>
<%= f.file_field :avatar %><br>
<%= f.submit "Submit Recipe" %>
<% end %>
I am fairly new to Rails so I may have missed something fundamental, or is it because it is a nested form and it behaves differently?
Edit
Output of <%= flash debug %>:
--- !ruby/object:ActionDispatch::Flash::FlashHash
used: !ruby/object:Set
hash: {}
closed: false
flashes: {}
now:
It seems you're not actually providing your flash hash with any messages to work with. A quick solution might be something like:
def create
#recipe = current_user.recipes.new(params[:recipe])
if #recipe.save
redirect_to my_recipes_path, :notice => "Thanks #{current_user.name} Recipe sucessfully created."
else
flash[:error] = #recipe.errors.full_messages.to_sentence
render :action => 'new'
end
end