Can't get nested form to show - ruby-on-rails

Below are my models:
class Ticket < ActiveRecord::Base
attr_accessible :issue, :logs_attributes
has_many :logs
accepts_nested_attributes_for :logs
end
class Log < ActiveRecord::Base
attr_accessible :detail, :ticket_id
belongs_to :ticket
end
I'm trying to figure out how to create new log via the ticket view, but I can't get the detail field in the log model to show.
My attempt on the views:
tickets_form
<%= form_for(#ticket) do |f| %>
<% if ... end %>
<div class="field">
<%= f.label :issue %><br />
<%= f.text_area :issue %>
</div>
<% f.fields_for :logs do |builder| %>
<p>
<%= builder.label :detail %><br />
<%= builder.text_area :detail %>
</p>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
tickets\show
<p id="notice"><%= notice %></p>
<p>
<b>Issue:</b>
<%= #ticket.issue %>
</p>
<ol>
<% for log in #ticket.logs %>
<p>
<%=log.detail %> *Note:squiggly line under detail said "Cannot find 'detail'"*
</p>
<% end %>
</ol>
<%= link_to 'Edit', edit_ticket_path(#ticket) %> |
<%= link_to 'Back', tickets_path %>
My Controller:
def new
#ticket = Ticket.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #ticket }
end
end
def create
#ticket = Ticket.new(params[:ticket])
respond_to do |format|
if #ticket.save
format.html { redirect_to #ticket, notice: 'Ticket was successfully created.' }
format.json { render json: #ticket, status: :created, location: #ticket }
else
format.html { render action: "new" }
format.json { render json: #ticket.errors, status: :unprocessable_entity }
end
end
end
Ticket\show
<h1>New ticket</h1>
<%= render 'form' %>
<%= link_to 'Back', tickets_path %>

Your attr_accessible line in Ticket class should be attr_accessible :issue, :logs_attributes.
Otherwise you should get(if you are using rails version < 4):
Can't mass-assign protected attributes: logs_attributes
If you don't get it there must be a problem with your controller create action(can you update your question with a controller code?)
It should look something like this:
def new
#ticket = Ticket.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #ticket }
end
end
def create
#ticket = Ticket.new(params[:ticket])
respond_to do |format|
if #ticket.save
format.html { redirect_to #ticket, notice: 'Ticket was successfully created.' }
format.json { render json: #ticket, status: :created, location: #ticket }
else
format.html { render action: "new" }
format.json { render json: #ticket.errors, status: :unprocessable_entity }
end
end
end
This simple create action together with fields_for call in your tickets_form and accepts_nested_attributes_for :logs in Ticket class will crate both parent and association object in a one go.
tickets/new.html.erb should look something like this:
<h1>New ticket</h1>
<%= render 'form' %>
<%= link_to 'Back', tickets_path %>
And the form partial tickets/_form.html.erb should be:
<%= form_for(#ticket) do |f| %>
<% if ... end %>
<div class="field">
<%= f.label :issue %><br />
<%= f.text_area :issue %>
</div>
<% f.fields_for :logs do |builder| %>
<p>
<%= builder.label :detail %><br />
<%= builder.text_area :detail %>
</p>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Off topic:
A bit more Rails way to do this(just a suggestion):
<% for log in #ticket.logs %>
<p>
<%=log.detail %>
</p>
<% end %>
Would be:
<% #ticket.logs.each |log| %>
<%= content_tag(:p, log.detail) %>
<% end %>

Related

Unpermitted parameters & unable to display nested fields_for

I am building simple ROR app which has survey question and answers. Survey is generated using scaffolding method while question and answer are model only.
Survey.rb
class Survey < ApplicationRecord
has_many :questions
accepts_nested_attributes_for :questions, allow_destroy: true
validates :name, presence: true
end
Question.rb
class Question < ApplicationRecord
belongs_to :survey
has_many :answers
accepts_nested_attributes_for :answers
validates :question_content, presence: true
end
Answer.rb
class Answer < ApplicationRecord
belongs_to :question
end
survey_controller.rb
class SurveysController < ApplicationController
before_action :set_survey, only: [:show, :edit, :update, :destroy]
def index
#surveys = Survey.all
end
def show
#survey= Survey.find(params[:id])
end
def new
#survey = Survey.new
#questions = #survey.questions.new
#answers = #questions.answers.new
end
def edit
end
def create
#survey = Survey.new(survey_params)
Survey.create(survey_params)
respond_to do |format|
if #survey.save
format.html { redirect_to #survey, notice: 'Survey was successfully created.' }
format.json { render :show, status: :created, location: #survey }
else
format.html { render :new }
format.json { render json: #survey.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #survey.update(survey_params)
format.html { redirect_to #survey, notice: 'Survey was successfully updated.' }
format.json { render :show, status: :ok, location: #survey }
else
format.html { render :edit }
format.json { render json: #survey.errors, status: :unprocessable_entity }
end
end
end
def destroy
#survey.destroy
respond_to do |format|
format.html { redirect_to surveys_url, notice: 'Survey was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_survey
#survey = Survey.find(params[:id])
end
def survey_params
params.require(:survey).permit(:name, questions_attributes: [:id, :question_content], answers_attributes: [:id, :answer_content, :answer_type])
end
end
Survey form partial
<%= form_for(#survey) do |form| %>
<% if survey.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(survey.errors.count, "error") %> prohibited this survey from being saved:</h2>
<ul>
<% survey.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :name %>
<%= form.text_field :name, id: :survey_name %>
</div>
<%= form.fields_for :questions do |builder| %>
<fieldset>
<%= builder.label :question_content, "Question" %><br/>
<%= builder.text_area :question_content %><br/>
<%= form.fields_for :answers do |f| %>
<fieldset>
<%= f.text_area :answer_type %>
<%= f.text_area :answer_content %><br/>
</fieldset>
</fieldset>
<% end %>
<%end %>
<div class="actions">
<%= form.submit %>
</div>
I want to implement question and answer in single page i.e survey. Any help will appreciated.
Problem : Unable to save answers_attributes to database but Question attributes work perfectly fine. I am probably making mistake somewhere in controller not sure.
You need to change the way you're building the answer fields, so that they're referenced as fields_for questions, not surveys. Try changing this piece of code:
<%= form.fields_for :questions do |builder| %>
<fieldset>
<%= builder.label :question_content, "Question" %><br/>
<%= builder.text_area :question_content %><br/>
<%= form.fields_for :answers do |f| %>
<fieldset>
<%= f.text_area :answer_type %>
<%= f.text_area :answer_content %><br/>
</fieldset>
</fieldset>
<% end %>
<%end %>
to this:
<%= form.fields_for :questions do |builder| %>
<fieldset>
<%= builder.label :question_content, "Question" %><br/>
<%= builder.text_area :question_content %><br/>
<%= builder.fields_for :answers do |f| %>
<fieldset>
<%= f.text_area :answer_type %>
<%= f.text_area :answer_content %><br/>
</fieldset>
<% end %>
</fieldset>
<% end %>
(Note: the meaningful change is changing form.fields_for to builder.fields_for)

Rails saving all my fields as nil

It creates the object, says that it was successfully created, but all fields are saved in the database with nil values. Only created_at and updated_at are saved normally.
Some methods of my controllers/admin/categories_controller.rb
def new
#admin_category = Category.new
end
# GET /admin/categories/1/edit
def edit
end
# POST /admin/categories
# POST /admin/categories.json
def create
#admin_category = Category.new(params[:category])
respond_to do |format|
if #admin_category.save
format.html { redirect_to admin_category_path(#admin_category), notice: 'Category was successfully created.' }
format.json { render :show, status: :created, location: admin_category_path(#admin_category) }
else
format.html { render :new }
format.json { render json: #admin_category.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /admin/categories/1
# PATCH/PUT /admin/categories/1.json
def update
respond_to do |format|
if #admin_category.update(admin_category_params)
format.html { redirect_to #admin_category, notice: 'Category was successfully updated.' }
format.json { render :show, status: :ok, location: #admin_category }
else
format.html { render :edit }
format.json { render json: #admin_category.errors, status: :unprocessable_entity }
end
end
end
This is my models/category model:
class Category < ActiveRecord::Base
belongs_to :category
end
This is my routes.br file
namespace :admin do
resources :categories
end
My views/admin/categories/_form.html.erb
<%= form_for(#admin_category, url: admin_categories_path) do |f| %>
<% if #admin_category.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#admin_category.errors.count, "error") %> prohibited this admin_category from being saved:</h2>
<ul>
<% #admin_category.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :is_active %><br>
<%= f.check_box :is_active %>
</div>
<div class="field">
<%= f.label :main_menu %><br>
<%= f.check_box :main_menu %>
</div>
<div class="field">
<%= f.label :category_id %><br>
<%= f.number_field :category_id %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
And when I try to edit, I get this error:
No route matches [PATCH] "/admin/categories"
I'm very newbie to Ruby on Rails, so I would apreciate any help!
Thanks!
You are only passing :category when creating a new Category:
def create
#admin_category = Category.new(params[:category])
Change it to Category.new(user_params) and try again. This will pass on all parameters you're creating and feed it to the database.
Also, permit the parameters you are trying to pass:
def user_params
params.require(:admin_category).permit(:name, :is_active, :main_menu, :category_id)
end
Strong Params:
#app/controllers/categories_controller.rb
class CategoriesController < ApplicationController
def create
#admin_category = Category.new category_params
end
private
def category_params
params.require(:category).permit(:name, :is_active, :main_menu, :category_id)
end
end
--
As a tip, if you're using nested objects with forms, you can pass both objects in an array to create the nested path:
#app/views/admin/categories/new.html.erb
<%= form_for [:admin, #admin_category] do |f| %>

NoMethodError in Spree::Admin::Societies#new undefined method `societies_path'

I am new to spree and ruby on rails. while creating a custom controller in my spree app, I can successfully add link to it in spree admin panel using deface. but when I go to that link, it gives me following error
NoMethodError in Spree::Admin::Societies#new
Showing app/views/spree/admin/societies/_form.html.erb where line #1 raised:
undefined method `societies_path' for #<#<Class:0x007f19cb636898>:0x007f19c5ecacf8>
I don't know from where it is looking for 'societies_path' as I already have updated app/views/spree/admin/societies/new.html.erb to look for 'admin_societies_path', here it is
<%= render 'form' %>
<%= link_to 'Back', admin_societies_path %>
and app/views/spree/admin/societies/_form.html.erb contains
<%= form_for(#society) do |f| %>
<% if #society.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#society.errors.count, "error") %> prohibited this society from being saved:</h2>
<ul>
<% #society.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :address %><br>
<%= f.text_field :address %>
</div>
<div class="field">
<%= f.label :area %><br>
<%= f.text_field :area %>
</div>
<div class="field">
<%= f.label :postcode %><br>
<%= f.number_field :postcode %>
</div>
<div class="field">
<%= f.label :city %><br>
<%= f.text_field :city %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
I tried removing link to back also, but it's again giving same error.
config/routes.rb is
mount Spree::Core::Engine, :at => '/'
Spree::Core::Engine.add_routes do
namespace :admin do
resource :societies
end
end
and my app/controllers/spree/admin/societies_controller.rb is
module Spree
module Admin
class SocietiesController < Spree::Admin::BaseController
before_action :set_society, only: [:show, :edit, :update, :destroy]
def index
#societies = Society.all
end
def show
end
def new
#society = Society.new
end
def edit
end
def create
#society = Society.new(society_params)
respond_to do |format|
if #society.save
format.html { redirect_to #society, notice: 'Society was successfully created.' }
format.json { render :show, status: :created, location: #society }
else
format.html { render :new }
format.json { render json: #society.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #society.update(society_params)
format.html { redirect_to #society, notice: 'Society was successfully updated.' }
format.json { render :show, status: :ok, location: #society }
else
format.html { render :edit }
format.json { render json: #society.errors, status: :unprocessable_entity }
end
end
end
def destroy
#society.destroy
respond_to do |format|
format.html { redirect_to societies_url, notice: 'Society was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_society
#society = Society.find(params[:id])
end
def society_params
params.require(:society).permit(:name, :url, :building_number, :address, :area, :postcode, :city, :active, :IsDelete)
end
end
end
end
Any help would be greatly appreciated.
I would suspect that it is this line in _form partial
<%= form_for(#society) do |f| %>
You need to reference the namespace here, so maybe somthing like
<%= form_for([:admin, #society]) do |f| %>
or add your own url
<%= form_for(#society, url: admin_societies_path) do |f| %>

After updating, file fields are duplicating in rails 4 using carrierwave gem

I am using rails 4 and carrierwave gem to uplaod files. I have a product and assets model. Product has_many assets and a nested form is used to save the assets in product. When i update any product, its assets field get duplicated and when I edit same product again I can see 8 fields in the form in place of 4 fields.
Product.rb
class Product < ActiveRecord::Base
has_many :assets , :dependent => :delete_all
accepts_nested_attributes_for :assets
Asset.rb
class Asset < ActiveRecord::Base
mount_uploader :asset1, AssetUploader
mount_uploader :asset2, AssetUploader
mount_uploader :asset3, AssetUploader
mount_uploader :asset4, AssetUploader
end
Product controller
def new
#product = Product.new
#product.assets.build
end
def create
#product = Product.new(product_params)
respond_to do |format|
if #product.save
format.html { redirect_to product_product_detail_path(#product), notice: 'Product was successfully created.' }
format.json { render action: 'show', status: :created, location: #product }
else
format.html { render action: 'new' }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #product.update(product_params)
format.html { redirect_to sub_category_path(#product.sub_category_id), notice: 'Product was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
new_html.erb for product
<%= form_for(#product, html: { multipart: true }) do |f| %>
<%= f.fields_for :assets do |asset| %>
<div class="field">
<%= asset.label :asset, "File #1" %>
<% unless asset.object.asset1.file.nil? %>
<%= image_tag(asset.object.asset1.url) %>
<p><% asset.object.asset1.file.filename %></p>
<p style="float:left">Change File?</p>
<% end %>
<%= asset.file_field :asset1 %>
</div>
<div class="field">
<%= asset.label :asset, "File #2" %>
<% unless asset.object.asset2.file.nil? %>
<%= image_tag(asset.object.asset2.url) %>
<p><% asset.object.asset2.file.filename %></p>
<p style="float:left">Change File?</p>
<% end %>
<%= asset.file_field :asset2 %>
</div>
<div class="field">
<%= asset.label :asset, "File #3" %>
<% unless asset.object.asset3.file.nil? %>
<%= image_tag(asset.object.asset3.url) %>
<p><% asset.object.asset3.file.filename %></p>
<p style="float:left">Change File?</p>
<% end %>
<%= asset.file_field :asset3 %>
</div>
<div class="field">
<%= asset.label :asset, "File #4" %>
<% unless asset.object.asset4.file.nil? %>
<%= image_tag(asset.object.asset4.url) %>
<p><% asset.object.asset4.file.filename %></p>
<p style="float:left">Change File?</p>
<% end %>
<%= asset.file_field :asset4 %>
</div>
<% end %>
<div class="actions">
<%= f.submit :class=> "action-btn" %>
</div>
<% end %>
UPDATE-
def product_params
params.require(:product).permit(assets_attributes: [:asset, :asset1, :asset2, :asset3, :asset4 ])
end
def edit
end
Please help me to solve the issue.
Try (id for update):
def product_params
params.require(:product).permit(assets_attributes: [:id, :asset, :asset1, :asset2, :asset3, :asset4 ])
end

Dealing has_one and singular resource with nested resource

I have a User model, which has_one prestataire and has_one employeur. Previously on stackoverflow, someone advised me to declare singular resources, like:
resources :users do
resource: employeur
resource: prestataire
end
Instead of:
resources :users do
resources: employeurs
resources: prestataires
end
Thanks to rails, I didn't had to singularize all my controllers and views name files. Yet, when I create a user and am redirected to the employeur form, I get undefined method `user_employeurs_path', which is right since I only have a user_employeur_path. But I didn't ask for the plural in my user controller. Rails indicates that this NoMethodError happens in the first line of my employeur form <%= form_for [#user, #employeur] do |f| %>, where one is redirected when a user is saved.
class UsersController < ApplicationController
#TODO index user doit être suprimé quand inutile pour dev
def index
#users = User.all
end
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
# GET /users/1/edit
def edit
#user = User.find(params[:id])
end
# POST /users
# POST /users.json
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
if params[:commit] == 'Prestataire'
format.html { redirect_to new_user_prestataire_path(user_id: #user), notice: "Renseignez vos informations d'employeur" }
format.json { render action: 'show', status: :created, location: #user }
else
format.html { redirect_to new_user_employeur_path(user_id: #user), notice: "Renseignez vos informations de prestataire" }
format.json { render action: 'show', status: :created, location: #user }
end
else
format.html { render action: 'new' }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /users/1
# PATCH/PUT /users/1.json
def update
#user = User.find(params[:id])
respond_to do |format|
if #user.update(user_params)
if params[:commit] == 'Prestataire'
format.html { redirect_to new_user_prestataire_path(user_id: #user), notice: 'User was successfully updated.' }
format.json { head :no_content }
else
format.html { redirect_to new_user_employeur_path(user_id: #user), notice: "User was successfully updated." }
format.json { head :no_content }
end
else
format.html { render action: 'edit' }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
#user = User.find(params[:id])
#user.destroy
respond_to do |format|
format.html { redirect_to users_url }
format.json { head :no_content }
end
end
private
def user_params
params.require(:user).permit(:email, :password, :password_confirmation, :surname, :forename, :civility, :phone)
end
end
User form:
<%= form_for(#user) do |f| %>
<% if #user.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#user.errors.count, "error") %> prohibited this user from being saved:</h2>
<ul>
<% #user.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :civility, 'Titre de civilité: ' %><br>
<%= f.text_field :civility %>
</div>
<div class="field">
<%= f.label :forename, 'Prénom: ' %><br>
<%= f.text_field :forename %>
</div>
<div class="field">
<%= f.label :surname, 'Nom de famille: ' %><br>
<%= f.text_field :surname %>
</div>
<div class="field">
<%= f.label :email, 'Email: ' %><br>
<%= f.text_field :email %>
</div>
<div class="field">
<%= f.label :password, 'Mot de passe: ' %><br>
<%= f.password_field :password, size: 40 %>
</div>
<div class="field">
<%= f.label :password_confirmation, 'Confirmation de mot de passe: ' %><br>
<%= f.password_field :password_confirmation, size: 40 %>
</div>
<div class="field">
<%= f.label :phone, 'Numéro de téléphone: ' %><br>
<%= f.text_field :phone %>
</div>
<div class="actions">
<%= f.submit "Employeur" %>
<%= f.submit "Prestataire" %>
</div>
<% end %>
Employeur form:
<%= form_for [#user, #employeur] do |f| %>
<% if #employeur.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#employeur.errors.count, "error") %> prohibited this employeur from being saved:</h2>
<ul>
<% #employeur.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :siren, 'Siren: ' %><br>
<%= f.text_field :siren %>
</div>
<div class="field">
<%= f.label :societe, 'Société: ' %><br>
<%= f.text_field :societe %>
</div>
<div class="field">
<%= f.label :code_postal, 'Code Postal: ' %><br>
<%= f.text_field :code_postal %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
As for my new.html document for employeur:
<h1>New employeur</h1>
<%= render 'form' %>
Here is what's happening:
when you pass <%= form_for [#user, #employeur] do |f| %>, Rails will connect the objects (#user & #employeur) in the order you passed and the then append path to it. So this becomes user_employeurs_path. by convention it will pluralize your the last object (employeur) to infer your controller's name. that's how it gets: user_employeurs_path
so you would either have to pluralize your controller's resources to follow the convention. Or pass url to your path:
<%= form_for [#user, #employeur], url: user_employeur_path do |f| %>
I believe you can use url parameter in this case. Try something like:
<%= form_for [#user, #employeur], url: user_employeur_path do |f| %>
...

Resources