My nested form fields for friends will not show no matter what i do..have the accepts_nested_attributes setup properly i believe?..
views/user_steps/show.html.erb
<%= simple_form_for #user do |f| %>
<%= f.input :city %>
<%= f.input :address %>
<%= f.input :zipcode %>
<%= f.input :date_of_birth %>
<%= f.input :gender, :collection => ['male','female'] %>
<%= f.association :interests, :as => :check_boxes, :label => false %>
<%= f.association :holidays, :as => :check_boxes, :label => false %>
<%= f.simple_fields_for :friends do |friend_f| %>
<%= friend_f.input :name %>
<%= friend_f.input :dob %>
<%= friend_f.input :gender %>
<% end %>
<%= f.button :submit %>
<%end%>
class UserStepsController < ApplicationController
def show
#user = current_user
end
def update
#user = current_user
#user.attributes = params[:user]
#friend = Friend.new(params[:friend])
end
def new
#user = User.new
#user.build_friend
end
end
class UsersController < ApplicationController
before_filter :authenticate_user!
def index
authorize! :index, #user, :message => 'Not authorized as an administrator.'
#users = User.paginate(:page => params[:page])
end
def show
#user = User.find(params[:id])
end
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'Friend birthday(1) was successfully created.' }
format.json { render json: #user, status: :created, location: #user }
else
format.html { render action: "new" }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
def update
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(params[:user])
format.html { redirect_to #user, notice: 'User was successfully updated.' }
format.json { head :no_content }
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
end
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation, :interests_attributes, :remember_me, :city, :zipcode, :date_of_birth, :gender, :address, :interest_ids, :holiday_ids
has_and_belongs_to_many :holidays
has_and_belongs_to_many :interests
has_many :friends
accepts_nested_attributes_for :friends, allow_destroy: true
accepts_nested_attributes_for :interests, allow_destroy: true
accepts_nested_attributes_for :holidays, allow_destroy: true
class Friend < ActiveRecord::Base
belongs_to :user
attr_accessible :dob, :gender, :name
end
My guess is that #user has no friends, so there's nothing to render.
If this is creating a new user and you want them to be able to fill in their friends as well, do a #user.friends.build somewhere, which will add an empty friend to them, and should allow the nested fields to render.
I've found this answer several times on the net. I'm using ruby-2.2.0 with rails 4.2.0. I'd like to know if this has changed, or if it's something specific to me.
I had to use. #user.build_friends
Related
I am creating a Single Table Inheritance model to build a comment thread and I am getting a confusing routing error
I have set up my Model
class Question < ApplicationRecord
has_many :answers, class_name: 'Questions::Answer'
end
class Answer < ApplicationRecord
has_many :answers, class_name: 'Answers::Answer'
end
with associated sub classes
module Questions
class Answer < ::Answer
belongs_to :question
validates :body, presence: true
validates :question, presence: true
end
end
module Answers
class Answer < ::Answer
belongs_to :answer
has_one :question, through: :answer
validates :body, presence: true
validates :answer, presence: true
end
end
Routes
resources :questions do
resources :answers, shallow: true
end
In my view, I render answers and a form to add an answer
<%= render #answers %></br>
<%= render "answers/form" %>
Which takes the following instances from my Question controller
def show
#answer = #question.answers.new
#answers = #question.answers.page(params[:page]).per(5)
end
However, this gives me an undefined method error:
undefined method `questions_answers_path'
In my routes, indeed the only paths are
question_answers GET /questions/:question_id/answers(.:format) answers#index
POST /questions/:question_id/answers(.:format) answers#create
new_question_answer GET /questions/:question_id/answers/new(.:format) answers#new
edit_answer GET /answers/:id/edit(.:format) answers#edit
answer GET /answers/:id(.:format) answers#show
PATCH /answers/:id(.:format) answers#update
PUT /answers/:id(.:format) answers#update
DELETE /answers/:id(.:format) answers#destroy
The question then is, why is it looking for the plural questions_answers_path, rather than question_answers_path.
The form is relatively standard:
<%= simple_form_for(#answer) do |f| %>
<%= f.error_notification %>
<%= f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present? %>
<div class="form-inputs">
<%= f.input :body %>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
When I force the path by using <%= simple_form_for #answer, url: question_answers_path(#question) do |f| %>
I get an error trying to submit the form. Body can't be blank
Any ideas on what is wrong with my code?
For completeness:
Answers Controller
class AnswersController < ApplicationController
before_action :set_answer, only: [:edit, :update, :destroy]
before_action :set_question
def create
#answer = #question.answers.build(answer_params)
respond_to do |format|
if #answer.save
format.html { redirect_to question_path(#question) }
format.json { render :show, status: :created, location: #answer }
else
format.html { render :new }
format.json { render json: #answer.errors, status: :unprocessable_entity }
end
end
end
def update
authorize #answer
respond_to do |format|
if #answer.update(answer_params)
format.html { redirect_to question_answers_path(#question), notice: 'Answer was successfully updated.' }
format.json { render :show, status: :ok, location: #answer }
else
format.html { render :edit }
format.json { render json: #answer.errors, status: :unprocessable_entity }
end
end
end
def destroy
authorize #answer
#answer = Answers.find(params[:id])
#answer.discard
respond_to do |format|
format.html { redirect_to question_answers_path(#question), notice: 'Answer was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_answer
#answer = Answer.find(params[:id])
end
def answer_params
params.fetch(:answer, {}).permit(:body, :type).merge(user_id: current_user.id, question_id: #question.id)
end
def set_question
#question = Question.find(params[:question_id])
end
end
I have a customer model and book_room model
class Customer < ApplicationRecord
has_many :book_rooms
accepts_nested_attributes_for :book_rooms
end
class BookRoom < ApplicationRecord
belongs_to :customer
end
in the book_room controller the create method is from its parent
class BookRoomsController < ApplicationController
def create
#customer = Customer.find(params[:customer_id])
#customer_room = #customer.book_rooms.create(book_rooms_params)
flash[:notice] = "Customer has been added to room"
redirect_to customer_path(#customer)
end
def destroy
#customer = Customer.find(params[:customer_id])
#customer_room = #customer.book_rooms.find(params[:id])
#customer_room.destroy
flash[:notice] = "Customer room has been deleted"
redirect_to customer_path(#customer)
end
def edit
#customer = Customer.find(params[:customer_id])
end
def update
#customer = Customer.find(params[:customer_id])
#customer.book_rooms.update(book_rooms_params)
flash[:notice] = "Customer has checked out"
redirect_to #customer
end
private
def book_rooms_params
params.require(:book_room).permit(:room, :first_name, :last_name, :phone_number, :checked_out)
end
end
in the Customer show page
<%= form_for [#customer, #customer.book_rooms.build] do |f| %>
<% #room = Room.all %>
<%= f.label "Room: "%>
<%= f.select(:room, #room.collect { |a| [a.room_number, a.id] }) %>
<%= f.submit "Enter" %>
<div class="col-md-12"><%= render #customer.book_rooms.order("created_at DESC") %></div>
This works perfectly and all child objects get created. now when I try to edit the child attributes it doesn't update at all
heres the edit form in the book_room edit page/action
<%= form_for #customer do |f| %>
<%= f.fields_for :book_rooms, #customer.book_rooms do |f| %>
<%= f.check_box :checked_out %>
<% end %>
<%= f.submit "Enter" %>
is there something i am doing wrong? why doesn't it update?
Customers controller
class CustomersController < ApplicationController
before_action :set_customer, only: [:show, :edit, :update, :destroy]
# POST /customers.json
def create
#customer = Customer.new(customer_params)
respond_to do |format|
if #customer.save
format.html { redirect_to #customer, notice: 'Customer was successfully created.' }
format.json { render :show, status: :created, location: #customer }
else
format.html { render :new }
format.json { render json: #customer.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #customer.update(customer_params)
format.html { redirect_to #customer, notice: 'Customer was successfully updated.' }
format.json { render :show, status: :ok, location: #customer }
else
format.html { render :edit }
format.json { render json: #customer.errors, status: :unprocessable_entity }
end
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_customer
#customer = Customer.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def customer_params
params.require(:customer).permit(:first_name, :last_name, :phone_number, :sex, :book_rooms_attributes => [:checked_out])
end
In your customers controller :
Try to change your function customer_params like:
def customer_params
params.require(:customer).permit(:first_name, :last_name, :phone_number, :sex, {:book_rooms => [:checked_out]})
end
For more explications see here
Change your update method to:
def update
#customer = Customer.find(params[:customer_id])
if #customer.update_attributes(customer_params)
flash[:notice] = "Customer has checked out"
redirect_to #customer
else
...redirect to edit page with a flash error message ...
end
end
You also need to modify your edit page.
<%= form_for(:customer, :url => {:action => 'update', :id => #customer.id}, :method => 'PUT') do |f| %>
Try changing the URL to update and changing the method to patch you will go to update method.
<%= form_for :customer, url: customer_path(#customer),method: :patch do |f| %>
<%= f.fields_for :book_rooms, #customer.book_rooms do |f| %>
<%= f.check_box :checked_out %>
<% end %>
<%= f.submit "Enter" %>
I have a problem a week ago with nested form. I have a model called users another Auto and another Perfil. I need that when a user creates a new Auto you can change your perfil data if needed
Please can you help me? We'll be very grateful
Try the following:
user model
class User < ActiveRecord::Base
has_many :autos
has_one :perfil
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
Auto model
class Auto < ActiveRecord::Base
belongs_to :user
belongs_to :perfil
accepts_nested_attributes_for :perfil, allow_destroy: true
end
Perfil Model
class Perfil < ActiveRecord::Base
belongs_to :user
has_many :autos
end
Auto Controller
class AutosController < ApplicationController
before_action :set_auto, only: [:show, :edit, :update, :destroy]
def new
#auto = Auto.new
#perfil = #auto.build_perfil
end
def create
#auto = Auto.new(auto_params)
#auto.user_id = current_user.id
#auto.perfil_id = current_user.perfil.id
respond_to do |format|
if #auto.save
format.html { redirect_to #auto, notice: 'Auto was successfully created.' }
format.json { render :show, status: :created, location: #auto }
else
format.html { render :new }
format.json { render json: #auto.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #auto.update(auto_params)
format.html { redirect_to #auto, notice: 'Auto was successfully updated.' }
format.json { render :show, status: :ok, location: #auto }
else
format.html { render :edit }
format.json { render json: #auto.errors, status: :unprocessable_entity }
end
end
end
private
def set_auto
#auto = Auto.find(params[:id])
end
def auto_params
params.require(:auto).permit(:perfil_id, :marca, :modelo, :año, :user_id, perfil_attributes: [:user_id, :nombre, :rut, :telefono, :direccion])
end
end
Perfil Controller
class PerfilsController < ApplicationController
before_filter :authenticate_user!
def show
current_user.perfil ||= Perfil.new
#perfil = current_user.perfil
end
def update
#perfil = current_user.perfil
respond_to do |format|
if current_user.perfil.update_attributes(perfil_params)
format.html {redirect_to root_path, notice: "Datos Actualizados" }
else
format.html {render action: "show"}
end
end
end
def create
current_user.perfil ||= Perfil.new
#perfil = current_user.perfil
respond_to do |format|
if current_user.perfil.update_attributes(perfil_params)
format.html {redirect_to root_path, notice: "Datos Actualizados" }
else
format.html {render action: "show"}
end
end
end
private
def perfil_params
params.require(:perfil).permit(:user_id, :nombre, :rut, :telefono, :direccion)
end
end
And _form.html.erb
<%= simple_form_for #auto do |f| %>
<div class="form-inputs">
<%= f.input :marca %>
<%= f.input :modelo %>
<%= f.input :año %>
<%= f.simple_fields_for :perfil, current_user.perfil do |p| %>
<%= p.input :nombre %>
<%= p.input :telefono %>
<%= p.input :direccion %>
<% end %>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
<%= link_to "Save", autos_path, :class => 'button_submit' %>
Routes.rb
Rails.application.routes.draw do
resources :autos
devise_for :users
resources :perfils, only: [:index,:show, :update , :create]
root 'autos#index'
end
This is almost perfect, just 2 little things will get you going.
1 The fields_for need only have :perfil as the object
<%= simple_form_for #auto do |f| %>
<div class="form-inputs">
<%= f.input :marca %>
<%= f.input :modelo %>
<%= f.input :año %>
<%= f.simple_fields_for :perfil do |p| %>
<%= p.input :nombre %>
<%= p.input :telefono %>
<%= p.input :direccion %>
<% end %>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
<%= link_to "Save", autos_path, :class => 'button_submit' %>
2 The controller needs to create the object as the current user
def create
#auto = current_user.autos.new(auto_params)
respond_to do |format|
if #auto.save
format.html { redirect_to #auto, notice: 'Auto was successfully created.' }
format.json { render :show, status: :created, location: #auto }
else
format.html { render :new }
format.json { render json: #auto.errors, status: :unprocessable_entity }
end
end
end
enter code here
<h1>Add New Investment Opportunity</h1>
<%= form_for Investopp.new do |f| %>
<div class="field">
<%= f.label :state_id %><br/>
<%= f.collection_select :state_id, Investopp.year_lookup(#state_ids), :label, :value, include_blank: true %>
</div>
<div class="field">
<%= f.label :city_id, "city" %><br />
<%= f.grouped_collection_select :city_id, Investopp.year_lookup(#state_ids), :cities, :value, :id,:name, include_blank: true %>
</div>
<% end %>
<%= link_to 'Back', investopps_path %>
<%= link_to 'Search', investopps_browsedisplay_path %>
class Investopp < ActiveRecord::Base
attr_accessible :Address, :Buildingname, :Desiredinvrole, :Details, :Prefferednoofinvestors, :Salesprice, :Weblisting, :photo, :user_id, :state_id, :city_id, :state, :city
has_attached_file :photo, :styles => { :small => "200x200>" }
belongs_to :user
validates :Buildingname, presence: true
validates :Address, presence: true
validates :Desiredinvrole, presence: true
validates :Weblisting, presence: true
validates :Details, presence: true
has_many :states
has_many :cities
def find_state(id)
if !id || id==0
id=1
end
#states= State.find(id)
#states.name
end
def find_city(id)
if !id || id==0
id=1
end
#cities= City.find(id)
#cities.name
end
def self.year_lookup(state_ids)
#create an emptycollection to hold the LabelValue Objects
years = []
state_ids.each do |yr| y = LabelValue.new()
y.label = yr
y.value = State.find_by_id(yr).name
years.push(y)
end
years
end
def self.state_lookup(state_ids)
years = []
state_ids.each do |yr| y = State.new()
y= State.find_by_id(yr)
years.push(y)
end
years
end
end
class LabelValue
# name the accessors. Label and Value
attr_accessor :label, :value
def cities
cityids=[]
state_cities=[]
investopps=Investopp.find(:all)
investopps.each do |i|
puts i.city_id
cityids <<i.city_id
end
cityids.uniq!
states=State.find_by_id(label)
cityids.each do |c|
if states.cities.find_by_id(c)
state_cities<< states.cities.find_by_id(c)
end
end
state_cities
end
end
class InvestoppsController < ApplicationController
# GET /investopps
# GET /investopps.json
def index
#investopps = Investopp.where(:user_id => current_user.id)
respond_to do |format|
format.html # index.html.erb
format.json { render json: #investopps }
end
end
# GET /investopps/1
# GET /investopps/1.json
def show
#investopp = current_user.investopps.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #investopp }
end
end
# GET /investopps/new
# GET /investopps/new.json
def new
#investopp = Investopp.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #investopp }
end
end
# GET /investopps/1/edit
def edit
#investopp = Investopp.find(params[:id])
end
# POST /investopps
# POST /investopps.json
def create
#params[:investopp][:state_id]= "gopi"
#params[:investopp][:city_id]= "33"
#investopp = current_user.investopps.build(params[:investopp])
respond_to do |format|
if #investopp.save
format.html { redirect_to #investopp, notice: 'Investopp was successfully created.' }
format.json { render json: #investopp, status: :created, location: #investopp }
else
format.html { render action: "new" }
format.json { render json: #investopp.errors, status: :unprocessable_entity }
end
end
end
# PUT /investopps/1
# PUT /investopps/1.json
def update
#investopp = Investopp.find(params[:id])
respond_to do |format|
if #investopp.update_attributes(params[:investopp])
format.html { redirect_to #investopp, notice: 'Investopp was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #investopp.errors, status: :unprocessable_entity }
end
end
end
# DELETE /investopps/1
# DELETE /investopps/1.json
def destroy
#investopp = Investopp.find(params[:id])
#investopp.destroy
respond_to do |format|
format.html { redirect_to investopps_url }
format.json { head :no_content }
end
end
def lis
#state_names=[]
#state_ids=[]
#city_ids= []
#city_names=[]
#investopp = Investopp.find(:all)
#investopp.each do |item|
#state_names<< State.find_by_id(item.state_id).name
#state_ids<< item.state_id
#city_names<< City.find_by_id(item.city_id).name
#city_ids << item.city_id
end
puts #state_ids.uniq!{|i| i}
puts #city_ids.uniq!{|i| i}
puts "gopi"
respond_to do |format|
format.html { render "investopps/lis", :locals => { :state_ids => #state_ids, :city_ids => #city_ids, :investopps => #investopp } }
format.json { render json: #investopp }
end
end
end
Instead of using <%= link_to 'Search', investopps_browsedisplay_path %> you should use <%= f.submit %> and specify the action correctly. So your form view will look like this:
<h1>Add New Investment Opportunity</h1>
<%= form_for Investopp.new, :action => investopps_browsedisplay_path do |f| %>
<div class="field">
<%= f.label :state_id %><br/>
<%= f.collection_select :state_id, Investopp.year_lookup(#state_ids), :label, :value, include_blank: true %>
</div>
<div class="field">
<%= f.label :city_id, "city" %><br />
<%= f.grouped_collection_select :city_id, Investopp.year_lookup(#state_ids), :cities, :value, :id,:name, include_blank: true %>
</div>
<%= link_to 'Back', investopps_path %>
<%= f.submit 'Search' %>
<% end %>
Then you'll also need a controller method handling things as the investopps_browsedisplay_path route, which I don't see in your code anywhere. This, of course, is not a RESTful way to handle this, and there's a needed caveat that your architecture will probably confuse the problem, but so far as sending the form data, the correct way to do it is with a form submit, not a link_to, which solves the basic problem at hand.
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|%>