rails nested_attributes form can't find id - ruby-on-rails

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

Related

simple_form not showing nested field

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

Missing file field in Nested Attributes

I'm using paperclip in nested attributes and I'm not sure what I'm missing. The view on the form is missing the file upload option.
Form
<%= form_with(model: news, local: true, html: { multipart: true } ) do |form| %>
<%= form.fields_for :images do |img| %>
<%= img.file_field :img, multiple: true %>
<% end%>
<% end %>
Models
class News < ApplicationRecord
has_many :images, dependent: :destroy
accepts_nested_attributes_for :images, allow_destroy: true
end
class Image < ApplicationRecord
belongs_to :news
has_attached_file :img, :styles => { :show => "600x600>" }, size: { less_than: 2.megabytes }
validates_attachment_content_type :img, :content_type => ["image/jpg", "image/jpeg", "image/gif", "image/png"]
end
Controller
class NewsController < ApplicationController
def new
#news = News.new
#news.images.build
end
def create
#news = News.new(news_params)
respond_to do |format|
if #news.save
format.html { redirect_to #news, notice: 'News was successfully created.' }
format.json { render :show, status: :created, location: #news }
else
format.html { render :new }
format.json { render json: #news.errors, status: :unprocessable_entity }
end
end
end
private
def set_news
#news = News.find(params[:id])
end
def news_params
params.require(:news).permit(:title, :description, :category, images_attributes: [:id, :img, :news_id, :_destroy])
end
end
If I change :images to :image in the form the field appears, but then gives an error on submission:
Unpermitted parameter: :image
In your case, you need to explicitly pass a record_object to the fields_for
<%= form.fields_for :images, #news.images.build do |img| %>
<%= img.file_field :img, multiple: true %>
<% end%>
Also in order to send multiple values for img, it should be an array in the permitted params. You should change the news_params to below
def news_params
params.require(:news).permit(:title, :description, :category, images_attributes: [:id, :news_id, :_destroy, img: []])
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) %>

Nested forms with three models through another one?

I have trying to create a nested form with three models associated with through in one.
This is the schema:
These are the models:
../app/models/alimento.rb:
class Alimento < ActiveRecord::Base
attr_accessible :calorias, :nome, :refeicaos_attributes
validates :nome, :calorias, :presence => { :message => "nao pode ficar em branco" }
has_many :controles, :dependent => :destroy
has_many :refeicaos, through: :controles
has_many :diarios, through: :controles
accepts_nested_attributes_for :controles
end
../app/models/refeicao.rb:
class Refeicao < ActiveRecord::Base
attr_accessible :nome, :alimentos_attributes, :controles_attributes, :diario_attributes
validates :nome, :presence => { :message => "nao pode ficar em branco" }
has_many :controles, dependent: :destroy
has_many :alimentos, through: :controles
has_many :diarios, through: :controles
accepts_nested_attributes_for :controles
end
../app/models/diario.rb:
class Diario < ActiveRecord::Base
has_many :controles, dependent: :destroy
has_many :refeicaos, through: :controles
has_many :alimentos, through: :controles
accepts_nested_attributes_for :controles
attr_accessible :data, :controles_attributes, :refeicaos_attributes, :alimentos_attributes
end
../app/models/controle.rb:
class Controle < ActiveRecord::Base
belongs_to :alimento
belongs_to :refeicao
belongs_to :diario
attr_accessible :quantidade, :alimento_id, :refeicao_id, :diario_id
accepts_nested_attributes_for :alimento
accepts_nested_attributes_for :refeicao
accepts_nested_attributes_for :diario
end
I created many alimentos (food) and refeições (meals), now I need create a
daily control of diet through the model Diario that can contain many alimentos and refeições through the Controle (control) model.
../app/controllers/diarios_controller.rb:
class DiariosController < ApplicationController
# GET /diarios
# GET /diarios.json
def index
#diarios = Diario.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #diarios }
end
end
# GET /diarios/1
# GET /diarios/1.json
def show
#diario = Diario.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #diario }
end
end
# GET /diarios/new
# GET /diarios/new.json
def new
#diario = Diario.new
end
# GET /diarios/1/edit
def edit
#diario = Diario.find(params[:id])
end
# POST /diarios
# POST /diarios.json
def create
#diario = Diario.new(params[:diario])
respond_to do |format|
if #diario.save
format.html { redirect_to #diario, notice: 'Diario was successfully created.' }
format.json { render json: #diario, status: :created, location: #diario }
else
format.html { render action: "new" }
format.json { render json: #diario.errors, status: :unprocessable_entity }
end
end
end
# PUT /diarios/1
# PUT /diarios/1.json
def update
#diario = Diario.find(params[:id])
respond_to do |format|
if #diario.update_attributes(params[:diario])
format.html { redirect_to #diario, notice: 'Diario was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #diario.errors, status: :unprocessable_entity }
end
end
end
# DELETE /diarios/1
# DELETE /diarios/1.json
def destroy
#diario = Diario.find(params[:id])
#diario.destroy
respond_to do |format|
format.html { redirect_to diarios_url }
format.json { head :no_content }
end
end
end
I'm trying to do the "Nested Model Form (revised)" example.
Views:
../app/views/diarios/new.html.erb:
<%= form_for #diario do |f| %>
<div class="field">
<%= f.label :data %>
<%= f.date_select :data %>
<br>
</div>
<%= f.fields_for :refeicaos do |builder| %>
<%= render 'refeicao_fields', f: builder %>
<% end %>
<%= link_to_add_fields "Adicionar Refeição", f, :refeicaos %>
</br>
</br>
<div class="actions">
<%= f.submit "Cadastrar Controle" %>
</div>
<% end %>
</br>
<%= link_to 'Voltar', root_path %>
../app/views/diarios/_refeicao_fields.html.erb:
<fieldset>
<strong>Refeição: </strong></br>
<%= f.label :nome, "Nome da Refeição", :style => 'margin-left: 5px;' %>
<%= collection_select(:refeicao, :id, Refeicao.order(:nome), :id, :nome) %>
<%= f.check_box :_destroy %>
<%= f.label :_destroy, "Remover Refeição" %>
</br>
</br>
<strong>Alimentos:</strong></br>
<%= f.fields_for :alimentos do |builder| %>
<%= render 'alimento_fields', f: builder %>
<% end %>
<%= link_to_add_fields "Adicionar Refeição", f, :alimentos %>
</fieldset>
../app/views/diarios/_alimento_fields.html.erb:
<fieldset>
<%= f.label :alimento, "Nome do Alimento:" %>
<%= collection_select(:alimento, :id, Alimento.order(:nome), :id, :nome) %>
<%= f.hidden_field :_destroy %>
<%= f.fields_for :controles do |builder| %>
<%= render 'controle_fields', f: builder %>
<% end %>
<%= link_to "Remover alimento", '#', class: "remove_fields" %></br>
</fieldset>
../app/views/diarios/_controle_fields.html.erb:
<fieldset>
<%= f.label :alimento, "Quantidade:", :style => 'margin-left: 42px;' %>
<%= f.number_field :quantidade, :style => 'width: 50px;' %>
</fieldset>
Custom helper created:
module ApplicationHelper
def link_to_add_fields(name, f, association)
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 + "_fields", f: builder)
end
link_to(name, '#', class: "add_fields", data: {id: id, fields: fields.gsub("\n", "")})
end
end
I get this error:
NoMethodError in Diarios#new
Showing D:/aplicacoes_indie/AppDieta/app/views/diarios/_refeicao_fields.html.erb where line #13 raised:
undefined method `alimentos' for nil:NilClass
Extracted source (around line #13):
10: <%= f.fields_for :alimentos do |builder| %>
11: <%= render 'alimento_fields', f: builder %>
12: <% end %>
13: <%= link_to_add_fields "Adicionar Refeição", f, :alimentos %>
14: </fieldset>
I've trying a lot of ways, but I can't solve this. The idea is: A Diario > with 1 or more refeicoes > with 1 or more alimentos and save each association through controle model.
Where am I wrong?
EDITED*
thanks for the answer, now the form appears
But should appear the number field 'quantidade' from controle below the select from alimento like this:
http://uploaddeimagens.com.br/images/000/123/917/full/model2.jpg?1385480010
../app/view/diarios/_alimento_fields.html.erb
<fieldset>
<%= f.label :alimento, "Nome do Alimento:" %>
<%= collection_select(:alimento, :id, Alimento.order(:nome), :id, :nome) %>
<%= f.hidden_field :_destroy %>
<%= f.fields_for :controles do |builder| %>
<%= render 'controle_fields', f: builder %>
<% end %>
<%= link_to "Remover alimento", '#', class: "remove_fields" %></br>
</fieldset>
../app/view/diarios/_controle_fields.html.erb
<fieldset>
<%= f.label :controle, "Quantidade:", :style => 'margin-left: 42px;' %>
<%= f.number_field :quantidade, :style => 'width: 50px;' %>
</fieldset>
One more thing, how can i mount the create action of Diario to get all the values of selects of alimentos and refeicaos and save each in controle model? Because I save and only create a Diario object with none association.
../app/controllers/diarios_controller.rb action create
def create
#diario = Diario.new(params[:diario])
respond_to do |format|
if #diario.save
format.html { redirect_to #diario, notice: 'Diario was successfully created.' }
format.json { render json: #diario, status: :created, location: #diario }
else
format.html { render action: "new" }
format.json { render json: #diario.errors, status: :unprocessable_entity }
end
end
end
I think these are the only accepts_nested_attributes_for statements that you should need:
class Diario < ActiveRecord::Base
accepts_nested_attributes_for :refeicaos
And:
class Refeicao < ActiveRecord::Base
accepts_nested_attributes_for :alimentos
Right now the <%= f.fields_for :refeicaos do |builder| %> statement is setting up the builder but builder.object is nil.
Edit - Changed field names to plural forms since this was a has_many relationship.
try:
class Alimento < ActiveRecord::Base
attr_accessible :calorias, :nome, :refeicaos_attributes
validates :nome, :calorias, :presence => { :message => "nao pode ficar em branco" }
has_many :controles, :dependent => :destroy
has_many :refeicaos, through: :controles
has_many :diarios, through: :controles
accepts_nested_attributes_for :controles
end
class Refeicao < ActiveRecord::Base
attr_accessible :nome, :alimentos_attributes, :controles_attributes, :diario_attributes
validates :nome, :presence => { :message => "nao pode ficar em branco" }
has_many :controles, dependent: :destroy
has_many :alimentos, through: :controles
has_many :diarios, through: :controles
accepts_nested_attributes_for :alimentos
end
class Diario < ActiveRecord::Base
has_many :controles, dependent: :destroy
has_many :refeicaos, through: :controles
has_many :alimentos, through: :controles
accepts_nested_attributes_for :refaicoas
attr_accessible :data, :controles_attributes, :refeicaos_attributes, :alimentos_attributes
end
class Controle < ActiveRecord::Base
belongs_to :alimento
belongs_to :refeicao
belongs_to :diario
attr_accessible :quantidade, :alimento_id, :refeicao_id, :diario_id
end

process collection_select on controller update actions

I have 2 models
The first model category.rb
class Category
include Mongoid::Document
# Relationships
has_many :boards, :dependent => :destroy , :autosave => true
accepts_nested_attributes_for :boards
#fields
field :name
#attr
attr_accessible :name, :boards_attributes
end
The second model its board.rb
class Board
include Mongoid::Document
#Relationships
belongs_to :category
#fields
field :name
field :description
#attr
attr_accessible :name, :description
end
I have in edit board view the next form:
<%= form_for [#board], :url => user_board_path do |f| %>
<%= f.text_field :name %>
<%= f.text_area :description, :cols =>72, :rows => 5, %>
<%= f.collection_select :category_id, Category.all, :id, :name%>
<% end %>
and I have in update action from boards_controller.rb the next:
def update
#board = Board.find(params[:id])
#category = Category.find(params[:category_id])
#board.category_id = #category
respond_to do |format|
if #board.update_attributes(params[:board])
format.html { redirect_to user_board_path(#board.user, #board), notice: 'Board was successfully updated.' }
format.json { head :ok }
else
format.html { render action: "edit" }
format.json { render json: #board.errors, status: :unprocessable_entity }
end
end
end
Why I get the #board.category_id nil? I want update the #board.category_id with the value that I choose in select
The problem is #board.category_id = #category (you set an Object to an id field). It should be
#board = Board.find(params[:id])
#category = Category.find(params[:category_id])
#board.category = #category
or if #category is not used in the controller nor in the view, you could write
#board = Board.find(params[:id])
#board.category_id = params[:category_id]
The second solution removes a "SELECT" request on the Categories

Resources