Strong Params won't save nested has_many - ruby-on-rails-4

I'm using Rails 4, and with it Strong Params. For some reason I can't save my nested parameters. I've looked at how to do it and even might've gotten it working in a different Rails app before. I know to permit draft_players_attributes and list all of it's accepted params in an array.
Here are the params coming in:
Started POST "/draft_groups" for 127.0.0.1 at 2013-12-04 22:55:32 -0500
User Load (1.6ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 ORDER BY "users"."id" ASC LIMIT 1
Processing by DraftGroupsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"2W3bs1U7+CEzsWl+jDi3xZi5CyldYeZXCz3KU6c+sYY=", "draft_group"=>{"name"=>"Best Group Ever", "draft_id"=>"3", "captain_id"=>"1"}, "draft_players"=>{"player_id"=>"1", "position"=>"Handler", "rating"=>"10", "info"=>"Smart"}, "commit"=>"Update"}
(0.3ms) BEGIN
SQL (2.6ms) INSERT INTO "draft_groups" ("captain_id", "created_at", "draft_id", "name", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["captain_id", 1], ["created_at", Thu, 05 Dec 2013 03:55:32 UTC +00:00], ["draft_id", 3], ["name", "Best Group Ever"], ["updated_at", Thu, 05 Dec 2013 03:55:32 UTC +00:00]]
(0.5ms) COMMIT
Redirected to http://lvh.me:3000/drafts/3
Completed 302 Found in 8ms (ActiveRecord: 3.3ms)
Here's my controller:
class DraftGroupsController < ApplicationController
def create
#draft_group = DraftGroup.create(draft_group_params)
redirect_to :back, :notice => "Draft Group successfully created."
end
def update
#draft_group = DraftGroup.find(params[:id])
#draft_group.update(draft_group_params)
redirect_to :back, :notice => "Draft Group successfully updated."
end
def destroy
#draft_group = DraftGroup.find(params[:id]).destroy
redirect_to :back, :notice => "Draft Group successfully destroyed."
end
private
def draft_group_params
params.require(:draft_group).permit(:name,
:draft_id,
:captain_id,
draft_players_attributes:
[
:_destroy,
:id,
:player_id,
:position,
:rating,
:info
]
)
end
end
And my models:
class DraftGroup < ActiveRecord::Base
has_many :draft_players, :dependent => :destroy
belongs_to :captain, :class_name => "User"
accepts_nested_attributes_for :draft_players
end
class DraftPlayer < ActiveRecord::Base
belongs_to :draft_group
belongs_to :player, class_name: "User"
end
And my view:
<% #groups.each do |group| %>
<div class="span6 group">
<h4><%= "#{group.name}" %></h4>
<%= simple_form_for(group, :html => { :class => "auto-width" } ) do |f| %>
<div class="row">
<%= f.input :name, :label => false %>
<%= f.hidden_field :draft_id %>
<%= f.hidden_field :captain_id %>
</div>
<table>
<tr>
<th>Player</th>
<th>Position</th>
<th>Rating</th>
<th>Info</th>
</tr>
<%= simple_fields_for :draft_players do |player| %>
<tr>
<td><%= player.input :player_id, :label => false, :as => :select, :collection => User.active %></td>
<td><%= player.input :position, :label => false %></td>
<td><%= player.input :rating, :label => false %></td>
<td><%= player.input :info, :label => false %></td>
</tr>
<% end %>
</table>
<div class="row">
<%= f.button :submit, "Update", :class => "btn btn-primary" %>
</div>
<% end %>
</div>
<% end %>
EDIT: Added view code, and will probably take table out, shifting it into using bootstraps columns layout.

To make sure parameters are nested correctly (and so Rails can understand nested model attributes) you should call f.simple_fields_for(:draft_players) rather than simple_fields_for(:draft_players).
In other words, call simple_fields_for on the FormBuilder object f rather than calling the helper directly.
That way Rails can look up and validate the nested association correctly.

Related

Data not saved in nested forms

I am trying to implement nested forms .
For reference https://www.driftingruby.com/episodes/nested-forms-from-scratch
However in this video they have used simple_form_for
but i have used fields_for
Now my problem is that data in main form is saved but data in nested form is not saved.
I have checked properly ,data is passed from view to controller of nested form
My CONTROLLER
class TShyainTouyouJoshinshosController < ApplicationController
def new
#t_shyain_touyou_joshinsho = TShyainTouyouJoshinsho.new
end
def create
#t_shyain_touyou_joshinsho = TShyainTouyouJoshinsho.new(t_shyain_touyou_joshinsho_params)
#t_shyain_touyou_joshinsho.assign_attributes(:created_by => current_m_user_login.user_id)
respond_to do |format|
if #t_shyain_touyou_joshinsho.save
format.html { redirect_to dashboard_path, notice: '登録は完了しました。' }
format.json { render :show, status: :created, location: #t_shyain_touyou_joshinsho }
else
format.html { render :new }
format.json { render json: #t_shyain_touyou_joshinsho.errors, status: :unprocessable_entity }
end
end
end
private
def t_shyain_touyou_joshinsho_params
params.require(:t_shyain_touyou_joshinsho).permit(:wfs_id,:joshinsho_bi,shyain_rirekis_attributes: [:id,:emp_type,:company_name,:_destroy])
end
end
MY MODEL
class TShyainTouyouJoshinsho < ActiveRecord::Base
self.primary_key='wfs_id'
has_many :shyain_rirekis, foreign_key: 't_shyain_touyou_joshinsho_id', dependent: :destroy
accepts_nested_attributes_for :shyain_rirekis, allow_destroy: true , reject_if: :all_blank
end
class ShyainRireki < ActiveRecord::Base
belongs_to :t_shyain_touyou_joshinsho, :foreign_key => 't_shyain_touyou_joshinsho_id'
end
VIEW MAIN FORM
<%= link_to_add_nested_form_shyain('✙ 社員履歴', f, :shyain_rirekis, class: 'btn btn-success') %>
<div class="append_nested_form_fields">
</div>
VIEW PARTIAL
<%= f.fields_for :shyain_rirekis do |ff| %>
<tr>
<td><%= ff.select :emp_type,TShyainTouyouJoshinsho::EMP_TYPE,{}, class: 'form-control' , :disabled => #disabled_field %></td>
<td><%= ff.text_field :company_name, class: 'form-control' , :disabled => #disabled_field %></td>
<td><%= ff.hidden_field :_destroy %>
<%= link_to '削除' ,'#' , class: " btn btn-xs btn-danger remove_record" %>
</td>
</tr>
<% end %>
MY HELPER
def link_to_add_nested_form_shyain(name, f, association, **args)
new_object = f.object.send(association).klass.new
id = new_object.object_id
fields = f.fields_for(association, new_object, child_index: id) do |builder|
render(association.to_s.singularize, f: builder, commute_object: new_object)
end
link_to(name, '#', class: "add_nested_shyain_rireki " + args[:class], data: {id: id, fields: fields.gsub("\n", "")})
end
MY JAVASCRIPT
$(document).ready(function(){
$('form').on('click', '.remove_record', function(event) {
$(this).prev('input[type=hidden]').val('1');
$(this).closest('tr').hide();
return event.preventDefault();
});
$('form').on('click', '.add_nested_shyain_rireki', function(event) {
var regexp, time;
time = new Date().getTime();
regexp = new RegExp($(this).data('id'), 'g');
$('.append_nested_form_fields').append($(this).data('fields').replace(regexp, time));
return event.preventDefault();
});
});
MIGRATION FILE
def change
create_table :t_shyain_touyou_joshinshos do |t|
t.integer :wfs_id
t.date :joshinsho_bi
end
end
def change
create_table :shyain_rirekis do |t|
t.references :t_shyain_touyou_joshinsho, index: true, foreign_key: true
t.string :emp_type
t.string :company_name
end
end
I am using wfs_id as primary key of my main form
Thankyou in advance
It seems that the association given was wrong
It works fine now
I changed my migrations as follows
def change
create_table :shyain_rirekis do |t|
t.integer :wfs_id
t.string :emp_type
t.string :company_name
end
end
MODEL CHANGES
class TShyainTouyouJoshinsho < ActiveRecord::Base
self.primary_key='wfs_id'
has_many :shyain_rirekis, foreign_key: 'wfs_id', dependent: :destroy
accepts_nested_attributes_for :shyain_rirekis, allow_destroy: true , reject_if: :all_blank
end
class ShyainRireki < ActiveRecord::Base
belongs_to :t_shyain_touyou_joshinsho, :foreign_key => 'wfs_id'
end
VIEW CHANGES
<%= link_to_add_nested_form_shyain('✙ 社員履歴', f, :shyain_rirekis, class: 'btn btn-success') %>
<div class="append_nested_form_fields">
<%= f.fields_for :shyain_rirekis do |builder| %>
<%= render 'shyain_rireki', f: builder %>
<% end %>
</div>
PARTIAL CHANGES
<tr>
<td><%= f.select :emp_type,TShyainTouyouJoshinsho::EMP_TYPE,{}, class: 'form-control' , :disabled => #disabled_field %></td>
<td><%= f.text_field :company_name, class: 'form-control' , :disabled => #disabled_field %></td>
<td><%= f.hidden_field :_destroy %>
<%= link_to '削除' ,'#' , class: " btn btn-xs btn-danger remove_record" %>
</td>
</tr>

Rails 4 nested form - nested models not saving

I am getting ready to give up on this... I 've searched every question on this, done multiple tests and I can't figure it out.
I am trying to create new records of a model (absences) through nested attributes (classroom -> students).
Here is a hash that I manually created and gets saved when I call
# hash: {"classroom"=>{"rank"=>"aaa", "grade_id"=>"", "students_attributes"=>{"0"=>{"last_name"=>"aaa", "first_name"=>"aaa", "absences_attributes"=>{"0"=>{"class_time"=>"1", "status"=>"valid"}}}}}, "id"=>"26"}
#classroom = Classroom.find(params["id"])
#classroom.update(params["classroom"])
This gives me:
(0.5ms) begin transaction
SQL (1.3ms) UPDATE "classrooms" SET "rank" = ?, "updated_at" = ? WHERE "classrooms"."id" = ? [["rank", "aaa"], ["updated_at", "2016-08-10 21:09:17.883875"], ["id", 26]]
SQL (0.2ms) INSERT INTO "students" ("last_name", "first_name", "classroom_id", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?) [["last_name", "aaa"], ["first_name", "aaa"], ["classroom_id", 26], ["created_at", "2016-08-10 21:09:17.897997"], ["updated_at", "2016-08-10 21:09:17.897997"]]
SQL (0.2ms) INSERT INTO "absences" ("class_time", "status", "student_id", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?) [["class_time", 1], ["status", "Αδικαιολόγητη"], ["student_id", 51], ["created_at", "2016-08-10 21:09:17.902018"], ["updated_at", "2016-08-10 21:09:17.902018"]]
(11.4ms) commit transaction
=> true
HOWEVER
when I get this hash through the form submission the update doesn't happen and no "absences" are getting created. Here is what the console looks like:
Processing by ClassroomsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"blabla",
"classroom"=>{"students_attributes"=>{"0"=>{"absences_attributes"=>{
"0"=>{"student_id"=>"50", "date"=>"2016/08/17", "class_time"=>"1", "status"=>"valid"},
"1"=>{"student_id"=>"50", "date"=>"2016/08/17", "class_time"=>"2", "status"=>"valid"},
"2"=>{"student_id"=>"50", "date"=>"2016/08/17", "class_time"=>"3", "status"=>"valid"},
"3"=>{"student_id"=>"50", "date"=>"2016/08/17", "class_time"=>"4", "status"=>"valid"},
"4"=>{"student_id"=>"50", "date"=>"2016/08/17", "class_time"=>"5", "status"=>"valid"},
"5"=>{"student_id"=>"50", "date"=>"2016/08/17", "class_time"=>"6", "status"=>"valid"},
"6"=>{"student_id"=>"50", "date"=>"2016/08/17", "class_time"=>"7", "status"=>"valid"}},
"id"=>"50"}}}, "id"=>"27"}
Classroom Load (0.2ms) SELECT "classrooms".* FROM "classrooms" WHERE "classrooms"."id" = ? LIMIT 1 [["id", 27]]
(0.1ms) begin transaction Student Load
(0.3ms) SELECT "students".* FROM "students" WHERE "students"."classroom_id" = ? AND "students"."id" = 50 [["classroom_id", 27]]
(0.1ms) commit transaction
Here is my Classrooms Controller
class ClassroomsController < ApplicationController
def new
#classroom = Classroom.new
#students = 30.times {#classroom.students.build}
end
def create
#classroom = Classroom.new(classroom_params)
if #classroom.save
redirect_to #classroom
else
flash.now[:danger] = "Try again."
render "new"
end
end
def show
#classroom = Classroom.find(params[:id])
end
def data
#classroom = Classroom.find(params[:id])
#classroom.students.each { |student| 7.times { student.absences.build } }
end
def update
#classroom = Classroom.find(params[:id])
#classroom.update_attributes(classroom_params)
redirect_to #classroom
end
private
def classroom_params
params.require(:classroom).permit(:id, :grade_id, :rank, students_attributes:
[:id, :classroom_id, :first_name, :last_name, absences_attributes:
[:id, :student_id, :date, :status, :class_time]])
end
end
Classroom Model
class Classroom < ActiveRecord::Base
# belongs_to :grade
has_many :students, inverse_of: :classroom, dependent: :destroy
accepts_nested_attributes_for :students, allow_destroy: true,
reject_if: proc { |a| [a[:first_name], a[:last_name]].any? {|b| b.blank?}}
has_many :absences, through: :students
accepts_nested_attributes_for :absences, allow_destroy: true,
reject_if: proc { |a| a[:status].blank? }
validates :rank, presence: true
end
Student Model
class Student < ActiveRecord::Base
belongs_to :classroom, inverse_of: :students
has_many :absences, inverse_of: :student
accepts_nested_attributes_for :absences, allow_destroy: true,
reject_if: proc { |a| a[:status].blank? }
# validates :first_name, presence: true
# validates :last_name, presence: true
def full_name
return last_name + " " + first_name
end
end
Absence Model
class Absence < ActiveRecord::Base
belongs_to :student, inverse_of: :absences
# validates :date, presence: true
# validates :class_time, presence: true
# validates :status, presence: true, inclusion: { in: ["valid",
# "invalid", "erased"] }
end
I have turned off all validations as to be sure this is not the reason they are not being saved.
Nested form view
<div id="absences" class="tab-pane fade in active">
<h3>Absences</h3>
<br>
<div class="input-group date col-md-3" id="datepicker">
<input type="text" class="form-control">
<div class="input-group-addon">
<span class="glyphicon glyphicon-th"></span>
</div>
</div>
<%= form_for #classroom do |class_f| %>
<% #classroom.students.each do |student| %>
<div class="student_<%= student.id %>">
<h4><%= student.full_name %></h4>
<div class="absences">
<p>
<% 7.times do |i| %>
<span><%= i + 1 %></span>
<% end %>
</p>
<%= class_f.fields_for :students, student do |student_f| %>
<% student.absences.each_with_index do |absence, i| %>
<div class="school-hour text-center" data-value="<%= i + 1 %>">
<%= fa_icon "plus" %>
<%= fa_stacked_icon "plus", base: "circle-o" %>
<%= fa_icon "minus" %>
<%= student_f.fields_for :absences, absence do |ab_f| %>
<%= ab_f.hidden_field :student_id, value: absence.student_id %>
<%= ab_f.hidden_field :date, class:"input-absence-date" %>
<%= ab_f.hidden_field :class_time, value: i + 1 %>
<%= ab_f.hidden_field :status, class:"input-absence-status" %>
<% end %>
</div>
<% end %>
<% end %>
</div>
</div>
<% end %>
<div class="actions">
<%= button_to "Submit", "#", class:"btn btn-primary"%>
</div>
<% end %>
</div>
The hidden fields without values are getting filled via javascript before form submission. I don't think that relates to the problem though. The params hash comes through, but the absences are not saving.
Without having spent a lot of time looking at this, could this be the problem?
reject_if: proc { |a| a[:status].blank? }
It appears the params are passing in status as "" which .blank? evaluates as true.
Whatever your form is passing in, in your first example you have "status"=>"valid" but in your 2nd example from the form "status"=>""
I found out that the problem was the reject_if on the classroom model.
I was trying to update the absence through the user, I wasn't actually changing the name of the user, and so not passing it as a param. As a result the record didn't pass the reject_if: proc { |a| [a[:first_name], a[:last_name]].any? {|b| b.blank?}} so it didn't reach the absence record at all. I tried putting a :new_record? validation in the reject if along with the other checks, but that didn't work out.
I found the solution in this answer: https://stackoverflow.com/a/13774269/5909738
Awesome and clean. Look at the comments as well.

Act-As-Taggable not saving to database

Hi I am attempting to use act_as_taggable ruby gem and have followed the github guide and a recent tutorial as well as checked stack overflow for advice. My code all seems to be correct but when I attempt to save tags via my form partial or via the rails console they do not save to the database.
Below relevant code excerpts.
Thanks in advance for any help!
post.rb
class Post < ActiveRecord::Base
acts_as_taggable
acts_as_taggable_on :tags
validates :title, presence: true, length: {minimum: 5}
validates :body, presence: true
extend FriendlyId
friendly_id :title, use: :slugged
end
post_controller.rb
class PostsController < ApplicationController
before_action :find_post, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
def index
if params[:tag].present?
#posts = Post.tagged_with(params[:tag]).paginate(:page => params[:page], :per_page => 10)
else
#posts = Post.all.order('created_at DESC').paginate(page: params[:page], per_page: 10)
end
end
def new
#post = Post.new
end
def show
end
def create
#post = Post.new(post_params)
if #post.save
redirect_to #post, notice: "Article succesfully saved!"
else
render 'new', notice: "Try Again. I was unable to save your post."
end
end
def edit
end
def update
if #post.update(params[:post].permit(:title, :body))
redirect_to #post, notice: "Article succesfully edited!"
else
render 'edit'
end
end
def destroy
#post.destroy
redirect_to posts_path
end
private
def post_params
params.require(:post).permit(:title, :body, :slug, :tag_list => [])
end
def find_post
#post = Post.friendly.find(params[:id])
end
end
routes.rb
Rails.application.routes.draw do
devise_for :users, :skip => :registrations
root 'pages#home'
resources :posts
resources :portfolios
get 'tags/:tag', to: 'posts#index', as: :tag
end
_form.html.erb
<%= form_for #post do |f| %>
<% if #post.errors.any? %>
<div id="errors">
<h2><%= pluralize(#post.errors.count, "error") %> prevented this post from saving:</h2>
<ul>
<% #post.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.label :title %><br>
<%= f.text_field :title, class: 'form-control form-control-lg' %><br>
<br>
<%= f.label :body %><br>
<%= f.text_area :body, class: 'form-control form-control-lg', :rows => "10" %><br>
<br>
<%= f.label :tag_list, "Tags (separated by commas)" %>
<%= f.text_field :tag_list, class: 'form-control' %>
<br>
<%= f.submit %>
<% end %>
excerpt from show.html.erb
<% #post.tags.any? %>
<% #post.tags.each do |tag| %>
<li><a href="#">
<%= link_to tag.name, tag_path(tag.name) %>
</a></li>
<% end %>
Params log for _form as requested by Pavan:
Started PATCH "/posts/my-third-post-with-tags" for ::1 at 2015-09-23 15:56:36 +1000
Processing by PostsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"GwLMImKSDyhPt77nI+fhIkF4QVsFxMen851wjcVorrxOCdU+TcRKIZv1im4/oNx7DERYCI91vE9YDjvSda7MAg==", "post"=>{"title"=>"My third post with tags", "body"=>"to update your local repository to the newest commit, execute\r\ngit pull\r\nin your working directory to fetch and merge remote changes.\r\nto merge another branch into your active branch (e.g. master), use\r\ngit merge <branch>\r\nin both cases git tries to auto-merge changes. Unfortunately, this is not always possible and results in conflicts. You are responsible to merge those conflicts manually by editing the files shown by git. After changing, you need to mark them as merged with\r\ngit add <filename>\r\nbefore merging changes, you can also preview them by using\r\ngit diff <source_branch> <target_branch>", "tag_list"=>"tag, css"}, "commit"=>"Update Post", "id"=>"my-third-post-with-tags"}
Post Load (0.1ms) SELECT "posts".* FROM "posts" WHERE "posts"."slug" = ? ORDER BY "posts"."id" ASC LIMIT 1 [["slug", "my-third-post-with-tags"]]
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT 1 [["id", 1]]
Unpermitted parameter: tag_list
(0.0ms) begin transaction
(0.0ms) commit transaction
Redirected to http://localhost:3000/posts/my-third-post-with-tags
Completed 302 Found in 4ms (ActiveRecord: 0.3ms)
Started GET "/posts/my-third-post-with-tags" for ::1 at 2015-09-23 15:56:36 +1000
Processing by PostsController#show as HTML
Parameters: {"id"=>"my-third-post-with-tags"}
Post Load (0.1ms) SELECT "posts".* FROM "posts" WHERE "posts"."slug" = ? ORDER BY "posts"."id" ASC LIMIT 1 [["slug", "my-third-post-with-tags"]]
ActsAsTaggableOn::Tag Exists (0.1ms) SELECT 1 AS one FROM "tags" INNER JOIN "taggings" ON "tags"."id" = "taggings"."tag_id" WHERE "taggings"."taggable_id" = ? AND "taggings"."taggable_type" = ? AND "taggings"."context" = ? LIMIT 1 [["taggable_id", 2], ["taggable_type", "Post"], ["context", "tags"]]
ActsAsTaggableOn::Tag Load (0.1ms) SELECT "tags".* FROM "tags" INNER JOIN "taggings" ON "tags"."id" = "taggings"."tag_id" WHERE "taggings"."taggable_id" = ? AND "taggings"."taggable_type" = ? AND "taggings"."context" = ? [["taggable_id", 2], ["taggable_type", "Post"], ["context", "tags"]]
Rendered posts/show.html.erb within layouts/application (3.2ms)
Rendered layouts/_header.html.erb (496.3ms)
Rendered devise/shared/_links.html.erb (0.2ms)
Rendered devise/sessions/_new.html.erb (4.6ms)
Rendered layouts/_slideoutpanels.html.erb (460.2ms)
Rendered layouts/_footer.html.erb (0.0ms)
Completed 200 OK in 1486ms (Views: 1484.3ms | ActiveRecord: 0.2ms)
Your error is from PostsController#update as HTML
In controller you don;t permit tag_list
#post.update(params[:post].permit(:title, :body))

Not sure why the VIEW does't work: Rails 4 nested attributes and has_many :through associaton in a form

I followed this page to build my app:
Rails 4 nested attributes and has_many :through associaton in a form
but it shows NOTHING in my VIEW:
(the weird thing is when i typed "f.fields_for :questionnaire_surveRys do |ff|" instead of the right one, it showed me the ocrrect page.
any suggestions will be greatly appreciated.
here are my Models:
questionnaire.rb
class Questionnaire < ActiveRecord::Base
has_many :questionnaire_surveys
has_many :surveys, through: :questionnaire_surveys
accepts_nested_attributes_for :questionnaire_surveys
end
questionnaire_survey.rb
class QuestionnaireSurvey < ActiveRecord::Base
belongs_to :questionnaire
belongs_to :survey
accepts_nested_attributes_for :survey
end
survey.rb
class Survey < ActiveRecord::Base
has_many :questions, :dependent => :destroy
accepts_nested_attributes_for :questions, :reject_if => lambda { |a| a[:content].blank? }, :allow_destroy => true
has_many :questionnaire_surveys
has_many :questionnaires, through: :questionnaire_surveys
end
and this is my questionnaire_controller.rb
def new
#questionnaire = Questionnaire.new
#surveys = Survey.all
end
def questionnaire_params
params.require(:questionnaire).permit(:name, questionnaire_surveys_attributes: [:id, survey_attributes:[:id]])
end
this is my _form.html.erb
<%= form_for(#questionnaire) do |f| %>
<p>
<%= f.label :name %><br/>
<%= f.text_field :name %>
<div class="field">
<%= f.fields_for :questionnaire_surveys do |ff| %>
<%= ff.fields_for :survey do |builder| %>
<% #surveys.each do |survey| %>
<%= builder.check_box :id, {}, survey.id %>
<%= builder.label survey.name %>
<% end %>
<% end %>
<% end %>
</div>
</p>
<div class="actions">
<%= f.submit %>
</div>
UPDATED:
Started POST "/questionnaires" for ::1 at 2015-07-29 22:45:16 +0800
Processing by QuestionnairesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"k4SkRC08PwAHAo1iERmQCkssdQZYgf+uHwofPdeLbXo0O4/psY3Y7i/krQA01omToQ4VLlt/YQDNkcbpLGp86w==", "questionnaire"=>{"name"=>"what just happened", "questionnaire_surveys_attributes"=>{"0"=>{"survey_attributes"=>{"name"=>""}}}}, "commit"=>"Create Questionnaire"}
Unpermitted parameter: name
(0.1ms) begin transaction
SQL (0.7ms) INSERT INTO "questionnaires" ("name", "created_at", "updated_at") VALUES (?, ?, ?) [["name", "what just happened"], ["created_at", "2015-07-29 14:45:16.374246"], ["updated_at", "2015-07-29 14:45:16.374246"]]
SQL (0.2ms) INSERT INTO "surveys" ("created_at", "updated_at") VALUES (?, ?) [["created_at", "2015-07-29 14:45:16.377439"], ["updated_at", "2015-07-29 14:45:16.377439"]]
SQL (0.1ms) INSERT INTO "questionnaire_surveys" ("questionnaire_id", "survey_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["questionnaire_id", "52"], ["survey_id", "38"], ["created_at", "2015-07-29 14:45:16.378845"], ["updated_at", "2015-07-29 14:45:16.378845"]]
(0.9ms) commit transaction
Redirected to http://localhost:3000/questionnaires/52
Completed 302 Found in 12ms (ActiveRecord: 2.0ms)
UPDATE - 2015/7/31
Started POST "/questionnaires" for ::1 at 2015-07-31 17:46:50 +0800
Processing by QuestionnairesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"t/00prIClAUVdqPFxOnkTaxRPhTdY082PAvHb/VQSO4QQh8LLrNz6z2Qg6fhJv3URnNePN6d0ZjukB67DrFZfw==", "questionnaire"=>{"name"=>"OMG", "questionnaire_surveys_attributes"=>{"0"=>{"survey_attributes"=>{"name"=>""}}}}, "commit"=>"Create Questionnaire"}
(0.2ms) begin transaction
SQL (0.7ms) INSERT INTO "questionnaires" ("name", "created_at", "updated_at") VALUES (?, ?, ?) [["name", "OMG"], ["created_at", "2015-07-31 09:46:50.440466"], ["updated_at", "2015-07-31 09:46:50.440466"]]
SQL (0.4ms) INSERT INTO "surveys" ("name", "created_at", "updated_at") VALUES (?, ?, ?) [["name", ""], ["created_at", "2015-07-31 09:46:50.446176"], ["updated_at", "2015-07-31 09:46:50.446176"]]
SQL (0.2ms) INSERT INTO "questionnaire_surveys" ("questionnaire_id", "survey_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["questionnaire_id", "53"], ["survey_id", "39"], ["created_at", "2015-07-31 09:46:50.450001"], ["updated_at", "2015-07-31 09:46:50.450001"]]
(0.9ms) commit transaction
Redirected to http://localhost:3000/questionnaires/53
Completed 302 Found in 22ms (ActiveRecord: 2.4ms)
UPDATE - 2015/8/05
I can't upload pics here, hope this is what you need:
<input placeholder="vision" type="text" name="questionnaire[questionnaire_surveys_attributes][0][survey_attributes][name]" id="questionnaire_questionnaire_surveys_attributes_0_survey_attributes_name">
UPDATE - 2015/8/11
_form.erb.html
<div class="field">
<% #surveys.each do |survey| %>
<%= check_box_tag "questionnaire[questionnaire_surveys_attributes][][survey_id]", survey.id %>
<%= label_tag survey.name %>
<% end %>
</div>
questionnaires_controller.rb
params.require(:questionnaire).permit(:name, questionnaire_surveys_attributes: [:survey_id])
def new
#questionnaire = Questionnaire.new
#surveys = Survey.all
end
UPDATE - 2015/8/17
I misused the has_many :through and accepts_nested_attributes_for.
In has_many:xxx :through case, there is xxx_ids.
In accepts_nested_attributes_for xxx case, there is xxx_attributes.
I used accepts_nested_attributes_for in both questionnaire.rband questionnaire_survey.rb , which is a mistake.
The correct way to do what I want is use the has_many :through only.
Then my questionnaire_controller.rb will have
def questionnaire_params
params.require(:questionnaire).permit(:name, :survey_id=>[])
end
in _form view, it should be
<%= check_box_tag "questionnaire[survey_id][]", survey.id %>
it's much easier now.
#Rich Peck thanks for all your help.
First things first - if you're not seeing the form elements appear, it's because you've not got it set up correctly in the backend.
For the longest time, I tried to set this up and was getting very frustrated that the embedded form would not appear. It wasn't until I sorted it out properly that it worked. It's called graceful degradation (I think) - whereby no error will appear, yet functionality will be impaired.
Firstly, I think you haven't built your associated objects in the controller:
#app/controllers/questionnaire_controller.rb
def new
#questionnaire = Questionnaire.new
# You need to build the associated objects, like this:
#questionnaire.questionnaire_surveys.build.build_survey
#surveys = Survey.all
end
--
Secondly, there is a better way to show checkboxes for your #surveys object:
<%= ff.fields_for :survey do |survey| %>
<%= survey.collection_check_boxes :survey_ids, #surveys, :id, :name %>
<% end %>
You can read up about collection_check_boxes here
--
Thirdly, you should definitely learn haml. You could write your entire form like this:
= form_for #questionnaire do |f|
.name
= f.label :name
= f.text_field :name
.field
= f.fields_for :questionnaire_surveys do |ff| %>
= ff.fields_for :survey do |survey| %>
= survey.collection_check_boxes :survey_ids, #surveys, :id, :name
.actions
= f.submit
--
Finally, don't use HTML elements as styling.
<p> & <br> should only be used as markup. If you're using them for styling effect, you'll end up causing problems with browser compatibility etc.
You need to let your CSS do the styling (colouring, size, position), and any on-page elements used as ways to separate the content of your application.
Update
Okay, so I've looked at your BitBucket:
You need to uncomment #questionnaire.questionnaire_surveys.build.build_survey in app/controllers/questionnaires_controller.rb#20
If you do that, it should work.
I cannot see any problems with the construct of the models and controllers. Are you sure you've refreshed etc?
I see you're calling <%= render "form" %> - try putting the form directly in the new view to test if it will work.
Also, have you tried using a simple way to add the extra fields, like this:
<%= f.fields_for :questionnaire_surveys do |ff| %>
<%= ff.fields_for :survey do |builder| %>
<% #surveys.each do |survey| %>
<%= builder.text_field :name, placeholder: survey.name %>
<% end %>
<% end %>
Finally, if you post your posted parameters after form submit, I'll be in a much stronger position to see any of the errors/problems you may have.
--
You can change your params to the following:
#app/controllers/questionnaires_controller.rb
...
def questionnaire_params
params.require(:questionnaire).permit(:name, questionnaire_surveys_attributes: [:id, survey_attributes:[:name]])
end

link to update model parameter yields missing or empty value error

I'm trying to give provide a series of links that when selected will update a corresponding user's parameter to that which is supplied by the link without rendering a form. The only problem I'm running into is that when it calls the update method I get: param is missing or the value is empty: user.
update method
def update
#user = User.find(params[:id])
if #user.update(user_params)
redirect_to list_path
flash[:success] = "User updated"
else
redirect_to list_path
flash[:alert] = "User not updated"
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation, :title, :role, :address, :phone)
end
link_to
<% User.all.each do |user| %>
<% if user.role == "new" %>
<tr>
<td><%= user.name %></td>
<td><%= user.title %></td>
<td><%= user.role %></td>
<td><%= link_to "Admin", update_user_path(id: user.id, :role => "admin"), :method => :put %> / <%= link_to "Moderator", '#' %> / <%= link_to "Member", '#' %> / <%= link_to "Other", '#' %></td>
</tr>
<% end %>
<% end %>
param.inspect
{"_method"=>"put",
"authenticity_token"=>"AUcV1swtGmRuDelTzLkbLd9Gmj6+phnHaSFRqrvDyETLoxNUQSaAgkes4ViWXoAZ33K5NZojVz9XdgIIsqJblA==",
"id"=>"2",
"role"=>"admin"}
From what I've found the params.inspect should have something like [:user] => before all the parameters listed, but I cannot figure out why it is not nor can I successfully find a way to clarify.
error:
param is missing or the value is empty: user
def user_params
**params.require(:user).permit(:name, :email, :password,**
:password_confirmation, :title, :role, :address, :phone)
end
end
Log after link select
Started PUT "/update_user?id=4&role=admin" for 97.78.175.155 at 2015-06-30 15:51:47 +0000
Cannot render console from 97.78.175.155! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
Processing by UsersController#update as HTML
Parameters: {"authenticity_token"=>"m+LcLOBL5NBXHQXD19o45/iV07/V1HiAXpykV+NiXIpRBtqubUB+Nn68DciNPaPT+KHwtPFRNnhgy/f16gPPWg==", "id"=>"4", "role"=>"admin"}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 1]]
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 4]]
Unpermitted parameters: _method, authenticity_token, id
(0.2ms) begin transaction
User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE (LOWER("users"."email") = LOWER('qwerty#poster.com') AND "users"."id" != 4) LIMIT 1
(0.1ms) rollback transaction
Redirected to https://rails-tutorial-hougthonbrad.c9.io/list
Completed 302 Found in 11ms (ActiveRecord: 0.7ms)
Started GET "/list" for 97.78.175.155 at 2015-06-30 15:51:47 +0000
Cannot render console from 97.78.175.155! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
Processing by UsersController#list as HTML
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 1]]
User Load (0.5ms) SELECT "users".* FROM "users"
Rendered users/list.html.erb within layouts/application (3.4ms)
Completed 200 OK in 172ms (Views: 165.1ms | ActiveRecord: 0.7ms)
Change your update action to the below.
def update
#user = User.find(params[:id])
if #user.update(user_params)
redirect_to list_path
flash[:success] = "User updated"
else
redirect_to list_path
flash[:alert] = "User not updated"
end
end
Update #1:
Looking at your params, you need to change your user_params like the below.
def user_params
params.require(:user).permit(:id, :name, :email, :password, :password_confirmation, :title, :role, :address, :phone)
end
Update #2:
Try changing your link_to to the below
<%= link_to "Admin", update_user_path(user, user: {:id => user.id, :role => "admin"}), :method => :put %>
You have params.require(:user) within your user_params.
That user hash is usually generated by form_for.
I would suggest to render a form with all fields hidden except the submit button for your use case.