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
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
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
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) %>
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
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