simple_form not showing nested field - ruby-on-rails

I am trying simple_form nested attributes as suggested in https://github.com/plataformatec/simple_form/wiki/Nested-Models
The thing is, when I render the form I just can see the submit button, but not the input field. What am I doing wrong?
_form.html.erb
<%= simple_form_for [:admin, #incident] do |f| %>
<%= f.error_notification %>
<%= f.simple_fields_for :comments do |builder| %>
<%= builder.input :info, label: "Informe de seguimiento" %>
<% end %>
<div class="form-actions">
<%= f.submit "Enviar", class: "btn btn-primary" %>
</div>
<% end %>
incidents_controller.rb
class Admin::IncidentsController < ApplicationController
before_action :set_incident, only: [:show, :edit, :update]
def index
#incidents = Incident.all
end
def show
end
def new
#incident = Incident.new
#incident.comments.build
end
def edit
end
def update
respond_to do |format|
if #incident.update(incident_params)
format.html { redirect_to #incident, notice: 'Incidencia actualizada actualizada con éxito.' }
format.json { render :show, status: :ok, location: #incident }
else
format.html { render :edit }
format.json { render json: #incident.errors, status: :unprocessable_entity }
end
end
end
private
def set_incident
#incident = Incident.find(params[:id])
end
def incident_params
params.require(:incident).permit(:info, :subject, :status, comments_attributes: [:info])
end
end
incident.rb
class Incident < ApplicationRecord
belongs_to :user, optional: true
has_many :comments, dependent: :destroy
accepts_nested_attributes_for :comments, allow_destroy: true, reject_if: proc { |attributes| attributes['info'].blank? }
enum status: [:abierto, :tramite, :pendiente, :cerrado]
after_initialize :set_default_status, :if => :new_record?
def set_default_status
self.status ||= :abierto
end
end
comment.rb
class Comment < ApplicationRecord
belongs_to :user, optional: true
belongs_to :incident
end

You need to add #incident.comments.build to the show action of Admin::IncidentsController. Now it has no comments, I suppose, so the form is empty.
And you need to add :id to comments_attributes, without it comment can't be saved. If you planning to have some 'Delete' checkbox for existing comments you also need to add :_destroy to the attributes array

Related

rails nested_attributes form can't find id

So i have two models : Internship and Review. I want the Review to be a nested_attributs of Internship. So that i can create an internship with a review.
My problem is that the review form integrated in the new form internship, doesn't find the id of the internship. It raise the errors 'Review internship must exist'
Internship.rb
has_many :reviews, foreign_key: "review_internship_id"
has_many :review_users, foreign_key: 'review_user_id', class_name:"User", through: :reviews
accepts_nested_attributes_for :reviews, allow_destroy: true
validates_associated :reviews
Review.rb
belongs_to :review_user, class_name: "User"
belongs_to :review_internship, class_name: "Internship"
Internship_controller
def new
#internship = Internship.new
#internship.reviews.new
end
def create
#internship = Internship.new(internship_params)
#internship.user = current_user
#internship.reviews.first.review_user_id = current_user.id
respond_to do |format|
if #internship.save
format.html { redirect_to #internship, notice: 'Expérience crée avec succès' }
format.json { render :show, status: :created, location: #internship }
else
format.html { render :new }
format.json { render json: #internship.errors, status: :unprocessable_entity }
end
end
end
private
def internship_params
params.require(:internship).permit(:adress, :zipcode, :city, :specialty, :organization, :population, :cursus, :title, :duration, :description, :region, :remuneration, :user_id, reviews_attributes: [:title, :notation, :description, review_internship_id: params[:internship_id], review_user_id: current_user.id])
end
The new form in internship new
<%= form_with(model: internship, local: true) do |form| %>
....
<!--NESTED ATTRIBUTS REVIEW-->
<%= form.fields_for :reviews do |p| %>
<%= p.label :titre %>
<%= p.text_field :title, class:"form-control" %>
<%= p.label :note %>
<%= p.number_field :notation, min: 1, max: 5, class:"form-control" %>
<%= p.label :description %>
<%= p.text_area :description, class:"form-control" %>
<% end %>
...
<% end %>
So this is what i've tried in Internship controller
#intership.reviews.review_internship_id = #internship.id
So that it can find the id of the internship. The error is "Review Internship must exist".
It did the same with "Review User", which was solved with #internship.reviews.first.review_user_id = current_user.id
Do you have any idea where the problem is, and how i can find the internship id with another way. I've also tried the params[:id]
Thanks for your help
:
You don't really need a user_id foreign key on reviews since it can get there through the interview:
class Review
belongs_to :internship
has_one :user, through: :interview
end
class Internship
belongs_to :user
has_many :reviews
end
class User
has_many :internships
has_many :reviews, through: :internships
end
And you definitely don't ever need to be manually assigning parent ids for nested records.
class IntershipsController < ApplicationController
def new
#internship = Internship.new
#internship.reviews.new
end
def create
#internship = Internship.new(internship_params) do |i|
i.user = current_user
end
respond_to do |format|
if #internship.save
format.html { redirect_to #internship, notice: 'Expérience crée avec succès' }
format.json { render :show, status: :created, location: #internship }
else
format.html { render :new }
format.json { render json: #internship.errors, status: :unprocessable_entity }
end
end
end
private
def internship_params
# use some line-breaks!
params.require(:internship)
.permit(
:adress, :zipcode, :city, :specialty,
:organization, :population, :cursus,
:title, :duration, :description,
:region, :remuneration, :user_id,
reviews_attributes: [
:id, :title, :notation, :description
]
)
end
end

Rails 5 - Strong Parameters for Nested Attributes on Associated Objects

I am trying to create a nested attribute form for my Request model.
My parameters are not saving correctly when the Create action is triggered. Though in my console, the data is structured correctly for how I want it to be entered.
The :quantity attribute is on the JoinTable model of RequestDrink.
How can I white-list these parameters correctly?
Console Output
Started POST "/requests" for 127.0.0.1 at 2017-06-08 12:38:40 -0400
Processing by RequestsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"3ljcH44E7ZrEXNztlgGacyA0nyumNsTX6NyMMu9N+3SY0rCRXSsj/hsg0JP8jtVfDFkcEWOWHi/VwHrgertlLg==", "request"=>{"concierge_name"=>"Alex", "concierge_number"=>"954-123-4567", "concierge_email"=>"alex#email.com", "client_name"=>"Adam", "client_number"=>"954-765-4321", "client_email"=>"adam#email.com", "hotel_employee"=>"0", "concierge_service"=>"0", "vip_promoter"=>"0", "arriving_with_client"=>"1", "client_alone"=>"0", "males"=>"", "females"=>"1", "table_minimum"=>"1000", "event_date_id"=>"1", "arrival_time(1i)"=>"2017", "arrival_time(2i)"=>"6", "arrival_time(3i)"=>"8", "arrival_time(4i)"=>"16", "arrival_time(5i)"=>"38", "drinks_attributes"=>[{"id"=>"1", "quantity"=>"1"}, {"id"=>"2", "quantity"=>""}, {"id"=>"3", "quantity"=>""}, {"id"=>"4", "quantity"=>""}], "commit"=>"Submit"}
Completed 404 Not Found in 18ms (ActiveRecord: 0.0ms)
ActiveRecord::RecordNotFound (Couldn't find Drink with ID=1 for Request with ID=):
app/controllers/requests_controller.rb:34:in `create'
app/models/request.rb
class Request < ApplicationRecord
has_many :request_drinks
has_many :drinks, through: :request_drinks
accepts_nested_attributes_for :drinks
end
app/models/drinks.rb
class Drink < ApplicationRecord
has_many :request_drinks
has_many :requests, through: :request_drinks
end
app/models/request_drink.rb
class RequestDrink < ApplicationRecord
belongs_to :request
belongs_to :drink
end
app/controllers/request_controller.rb
class RequestsController < ApplicationController
before_action :set_request, only: [:show,
:edit,
:update,
:destroy]
def index
redirect_to root_path unless admin_signed_in?
#requests = Request.search(params[:term], params[:filter], params[:page])
end
def show
end
def new
#request = Request.new
#drinks = Drink.active
#chasers = Chaser.active
#table_locations = TableLocation.active
#event_dates = EventDate.active
end
def edit
end
def create
#request = Request.new(request_params)
#request.people = (#request.males || 0) + (#request.females || 0)
#drinks = Drink.active
#chasers = Chaser.active
#table_locations = TableLocation.active
#event_dates = EventDate.active
respond_to do |format|
if #request.save
format.html { redirect_to thanks_path, notice: 'Request was successfully created.' }
format.json { render :show, status: :created, location: #request }
else
format.html { render :new }
format.json { render json: #request.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #request.update(request_params)
format.html { redirect_to #request, notice: 'Request was successfully updated.' }
format.json { render :show, status: :ok, location: #request }
else
format.html { render :edit }
format.json { render json: #request.errors, status: :unprocessable_entity }
end
end
end
def destroy
#request.destroy
respond_to do |format|
format.html { redirect_to requests_url, notice: 'Request was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_request
#request = Request.find(params[:id])
end
def request_params
params.require(:request).permit(:concierge_name,
:concierge_number,
:concierge_email,
:client_name,
:client_number,
:client_email,
:hotel_employee,
:concierge_service,
:vip_promoter,
:arriving_with_client,
:client_alone,
:people,
:males,
:females,
:table_minimum,
:arrival_time,
:comments,
:event_date_id,
:drinks_attributes => [:id, :quantity]
)
end
end
app/views/requests/_form.html.erb
<%= form_with(model: request, local: true) do |f| %>
...
<h4>Drinks</h4>
<% #drinks.all.each do |d| %>
<%= hidden_field_tag "request[drinks_attributes][][id]", d.id %>
<%= number_field_tag "request[drinks_attributes][][quantity]", 0, in: 0..10 %>
<%= d.name %>
<br />
<% end %>
...
<% end %>
The :quantity attribute is on the JoinTable model of RequestDrink.
Yet your are using drinks instead of request_drinks. Try changing your code to use the latter:
Model:
class Request < ApplicationRecord
has_many :request_drinks
has_many :drinks, through: :request_drinks
accepts_nested_attributes_for :request_drinks
end
View:
...
<%= hidden_field_tag "request[request_drinks_attributes][][id]", d.id %>
<%= number_field_tag "request[request_drinks_attributes][][quantity]", 0, in: 0..10 %>
...
Controller:
class RequestsController < ApplicationController
# other actions
def request_params
params.require(:request).permit(..., :request_drinks_attributes => [:id, :quantity])
end
end
Thank you, this worked as well as tweaking my parameters a little more. This is the completed code
app/models/request.rb
class Request < ApplicationRecord
has_many :request_drinks
has_many :drinks, through: :requests
accepts_nested_attributes_for :request_drinks
end
app/controllers/request_controller.rb
class RequestController < ApplicationRecord
...
def request_params
params.require(:request).permit(:concierge_name,
:concierge_number,
:concierge_email,
:client_name,
:client_number,
:client_email,
:hotel_employee,
:concierge_service,
:vip_promoter,
:arriving_with_client,
:client_alone,
:people,
:males,
:females,
:table_minimum,
:arrival_time,
:comments,
:is_deleted,
:approved,
:attended,
:event_date_id,
:request_drinks_attributes => [:request_id, :drink_id, :quantity]
:table_location_ids => []
)
end
end
app/views/requests/_form.html.erb
...
<h4>Drinks</h4>
<% #drinks.all.each do |d| %>
<%= hidden_field_tag "request[request_drinks_attributes][][request_id]", request.id %>
<%= hidden_field_tag "request[request_drinks_attributes][][drink_id]", d.id %>
<%= number_field_tag "request[request_drinks_attributes][][quantity]", 0, in: 0..10 %>
<%= d.name %>
<br />
<% end %>

Ruby on rails - adding multiple choice checkboxes - ERROR - undefined method `check_box_tag'

I'm tying do add a new kind of answers to my polls app. It will be a multiple choice with checkboxes. The user can choose one or more possible answers from the checkboxes presented.
I'm struggling to make it work, I'm getting the error:
NoMethodError in Replies#new
undefined method `check_box_tag' for #<ActionView::Helpers::FormBuilder:0x007fae8bd82f48>
right i have this models:
answer.rb
class Answer < ActiveRecord::Base
belongs_to :reply
belongs_to :question
belongs_to :possible_answer
end
poll.rb
class Poll < ActiveRecord::Base
validates_presence_of :title
has_many :questions
has_many :replies
end
possible_answer.rb
class PossibleAnswer < ActiveRecord::Base
belongs_to :question
end
question.rb
class Question < ActiveRecord::Base
belongs_to :poll
has_many :possible_answers
has_many :answers
accepts_nested_attributes_for :possible_answers, reject_if: proc { |attributes| attributes['title'].blank? }
end
reply.rb
class Reply < ActiveRecord::Base
belongs_to :poll
has_many :answers
accepts_nested_attributes_for :answers
end
In the views I have a reply/new.html.erb that already work for radio and open answer questions, by rendering the partial by kind:
<h1><%= #poll.title %></h1>
<%= form_for [ #poll, #reply ] do |f| %>
<%= f.fields_for :answers do |c| %>
<%= render c.object.question.kind, c: c %>
<% end %>
<p>
<%=f.submit 'Finish poll', class: 'btn btn-primary'%>
</p>
<% end %>
and the partial for the checkbox:
<p>
<%= c.label :value, c.object.question.title %>
</p>
<div class="checkbox">
<% c.object.question.possible_answers.each do |possible_answer| %>
<p>
<label>
<%= c.check_box_tag :possible_answer_id, possible_answer.id %>
<%= possible_answer.title %>
<%= c.hidden_field :question_id %>
</label>
</p>
<% end %>
</div>
replies_controller.rb
class RepliesController < ApplicationController
def new
#poll = Poll.find params[:poll_id]
#reply = #poll.replies.build
#poll.questions.each { |question| #reply.answers.build question: question }
end
def create
#poll = Poll.find params[:poll_id]
#reply = #poll.replies.build reply_params
if #reply.save
redirect_to #poll, notice: 'Thank you for the taking the poll.'
else
render :new
end
end
private
def reply_params
params.require(:reply).permit(:poll_id, {
answers_attributes: [:value, :question_id, :reply_id, :possible_answer_id] })
end
end
questions_controller
class QuestionsController < ApplicationController
before_action :set_question, only: [:show, :edit, :update, :destroy]
before_action :set_poll
before_action :set_kind_questions
def index
#questions = Question.all
end
def show
end
def new
##question = Question.new
#question = #poll.questions.build
5.times { #question.possible_answers.build }
end
def edit
end
def create
##question = Question.new(question_params)
#question = #poll.questions.build(question_params)
respond_to do |format|
if #question.save
format.html { redirect_to #poll, notice: 'Question was successfully created.' }
format.json { render :show, status: :created, location: #question }
else
format.html { render :new }
format.json { render json: #question.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #question.update(question_params)
format.html { redirect_to #question, notice: 'Question was successfully updated.' }
format.json { render :show, status: :ok, location: #question }
else
format.html { render :edit }
format.json { render json: #question.errors, status: :unprocessable_entity }
end
end
end
def destroy
#question.destroy
respond_to do |format|
format.html { redirect_to #question, notice: 'Question was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_question
#question = Question.find(params[:id])
end
def question_params
params.require(:question).permit(:title, :kind, :poll_id, { possible_answers_attributes: [:title, :question_id] })
end
def set_kind_questions
#kind_options = [
['Open Answer','open'],
['Multiple Radio Choice', 'radio'],
['Multiple Checkbox Choice','checkbox']
]
end
def set_poll
#poll = Poll.find params[:poll_id]
end
end
Answers migration table
class CreateAnswers < ActiveRecord::Migration
def change
create_table :answers do |t|
t.references :reply, index: true, foreign_key: true
t.references :question, index: true, foreign_key: true
t.references :possible_answer, index: true, foreign_key: true
t.string :value
t.timestamps null: false
end
end
end
Probably I have to use has_and_belongs_to_many association in the answers model but I'm not getting how. Can someone help me?
Thanks!
Please try to just use check_box_tag as below:
<%= check_box_tag( 'possible_answer_ids['+ possible_answer.id.to_s+']', possible_answer.id) %>

Form with nested resource: can't keep the association

I have a problem with a form with nested resource. The data model is easy:
class Event < ActiveRecord::Base
extend FriendlyId
friendly_id :name, use: [:slugged, :finders]
has_many :event_contents
end
class EventContent < ActiveRecord::Base
belongs_to :event
end
My form:
= simple_form_for([:admin, #event, #event.event_contents.new], remote: true) do |f|
.chat-form
.input-cont
= f.input :content, label: false, input_html: { class: 'form-control' }
.btn-cont
%span.arrow
= f.submit 'invia', class: 'btn blue icn-only'
The controller:
class Admin::EventContentsController < AdminController
def create
#event_content = EventContent.new event_content_params
#event_content.user_id = current_user.id if current_user
if #event_content.save
respond_to do |format|
format.js { render :nothing => true }
end
else
end
end
private
def event_content_params
params.require(:event_content).permit(
:content,
:event_id,
:user_id
)
end
end
When i submit the post in the params instead of event_id I have the event "slug"
pry(#<Admin::EventContentsController>)> params
=> {"utf8"=>"✓", "event_content"=>{"content"=>"uhm"}, "commit"=>"invia", "action"=>"create", "controller"=>"admin/event_contents", "event_id"=>"test-test-test"}
The record is created in the db, but event_id is nil so the association is broken.
Why instead of the event_id I have the event slug???
Update
The issue was the controller:
def create
#event = Event.find params[:event_id]
#event_content = #event.event_contents.build event_content_params
#event_content.user_id = current_user.id if current_user
if #event_content.save
respond_to do |format|
format.js
end
else
end
end
Maybe try doing the following:
in your Event model add accepts_nested_attributes_for :event_contents
in your form, when you are collecting the :event_contents replace
f.input :content, label: false, input_html: { class: 'form-control' }
with the following:
f.fields_for :event_contents do |content|
content.input :content
end
update your strong params in your Events controller to include {:event_contents_attributes} which might look something like below depending on the other params you need to pass through:
params.require(:event).permit(:name, {:event_contents_attributes => [:content]})
In your Events controller, update def new to include this line item event_content = #event.event_contents.build
All that to say, I believe you would want this to be routed to your Events controller and not your EventContents controller because the :event_contents are nested in the :event. It looks like your form is submitting to the EventContents controller currently. Also, I don't believe this argument in your simple_form_for #event.event_contents.new is necessary.
Here's what I built off of your question. It's not admin namespaced but might be helpful.
class EventsController < ApplicationController
def new
#event = Event.new
event_content = #event.event_contents.build
end
def create
#event = Event.new(event_params)
respond_to do |format|
if #event.save
format.html { redirect_to #event, notice: 'Event was successfully created.' }
format.json { render :show, status: :created, location: #event }
format.js
else
format.html { render :new }
format.json { render json: #event.errors, status: :unprocessable_entity }
end
end
private
def event_params
params.require(:event).permit(:name, {:event_contents_attributes => [:content]})
end
end
Event model:
class Event < ActiveRecord::Base
has_many :event_contents
accepts_nested_attributes_for :event_contents
end
And finally the form:
<%= form_for(#event) do |event| %>
<div class="field">
<%= event.label :name %><br>
<%= event.text_field :name %>
</div>
<%= event.fields_for :event_contents do |content| %>
<div class="field">
<%= content.label :content %>
<%= content.text_field :content %>
</div>
<% end %>
<div class="actions">
<%= event.submit %>
</div>
<% end %>

Why do I get a AssociationTypeMismatch when creating my model object?

I get the following error:
ActiveRecord::AssociationTypeMismatch in ContractsController#create
ExchangeRate(#2183081860) expected, got HashWithIndifferentAccess(#2159586480)
Params:
{"commit"=>"Create",
"authenticity_token"=>"g2/Vm2pTcDGk6uRas+aTgpiQiGDY8lsc3UoL8iE+7+E=",
"contract"=>{"side"=>"BUY",
"currency_id"=>"488525179",
"amount"=>"1000",
"user_id"=>"633107804",
"exchange_rate"=>{"rate"=>"1.7"}}}
My relevant model is :
class Contract < ActiveRecord::Base
belongs_to :currency
belongs_to :user
has_one :exchange_rate
has_many :trades
accepts_nested_attributes_for :exchange_rate
end
class ExchangeRate < ActiveRecord::Base
belongs_to :denccy, :class_name=>"Currency"
belongs_to :numccy, :class_name=>"Currency"
belongs_to :contract
end
My view is:
<% form_for #contract do |contractForm| %>
Username: <%= contractForm.collection_select(:user_id, User.all, :id, :username) %> <br>
B/S: <%= contractForm.select(:side,options_for_select([['BUY', 'BUY'], ['SELL', 'SELL']], 'BUY')) %> <br>
Currency: <%= contractForm.collection_select(:currency_id, Currency.all, :id, :ccy) %> <br> <br>
Amount: <%= contractForm.text_field :amount %> <br>
<% contractForm.fields_for #contract.exchange_rate do |rateForm|%>
Rate: <%= rateForm.text_field :rate %> <br>
<% end %>
<%= submit_tag :Create %>
<% end %>
My View Controller:
class ContractsController < ApplicationController
def new
#contract = Contract.new
#contract.build_exchange_rate
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #contract }
end
end
def create
#contract = Contract.new(params[:contract])
respond_to do |format|
if #contract.save
flash[:notice] = 'Contract was successfully created.'
format.html { redirect_to(#contract) }
format.xml { render :xml => #contract, :status => :created, :location => #contract }
else
format.html { render :action => "new" }
format.xml { render :xml => #contract.errors, :status => :unprocessable_entity }
end
end
end
I'm not sure why it's not recognizing the exchange rate attributes?
Thank you
The problem is that accepts_nested_attributes_for :exchange_rate looks for "exchange_rate_attributes" in the params, not "exchange_rate". The fields_for helper will do this for you, but you have to change it to:
<% contractForm.fields_for :exchange_rate do |rateForm|%>

Resources