Nested form fields for associated STI model - ruby-on-rails

I have a model Event that has one Payoption, which is a STI model. Payoption could be BankPayoption, CashPayoption etc, each of them has totally different fields.
The models, Payoption just have string attributes:
class Event < ActiveRecord::Base
has_one :payoption
end
class Payoption < ActiveRecord::Base
belongs_to :event
end
class BankPayoption < Payoption
end
class CashPayoption < Payoption
end
Event controller:
class EventsController < ApplicationController
def new
end
def create
#event = Event.new(post_params)
#event.user_id = current_user.id
#event.save
redirect_to #event
end
private
def post_params
params.require(:event).permit(:title, :text, :code)
end
end
This is the new Event view:
<%= form_for :event, url: events_path do |f| %>
<p>
<%= f.label :title %><br>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :text %><br>
<%= f.text_area :text %>
</p>
<p>
<%= f.label :code %><br>
<%= f.text_field :code %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
This code works fine but it's obviously not creating a Payoption association, I'm not sure how to implement this in the current form_for. I want to be able to pick on of the Payoption types with a select element and then the correct fields should show. I know the field show/hide action is done by javascript but the real problem is, how do I make a nested form that creates the chosen subclass and associates that with the event object?
Thanks

very simple do it this way
class EventsController < ApplicationController
def new
#event = Event.new
#event.build_payoption
end
end
<%= form_for(#event) do |f| %>
<p>
<%= f.label :title %><br>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :text %><br>
<%= f.text_area :text %>
</p>
<p>
<%= f.label :code %><br>
<%= f.text_field :code %>
</p>
<%= f.fields_for :payoption do |p| %>
<%= p.label :payoption_type %>
<%= p.select(:payoption_type, Payoption::PAY_OPTION , {:prompt => "Select"}, {class: "payoption"}) %>
<% end %>
<p>
<%= f.submit %>
</p>
<% end %>
class Event < ActiveRecord::Base
has_one :payoption, dependent: :destroy
accepts_nested_attributes_for :payoption
end
class Payoption < ActiveRecord::Base
belongs_to :event
PAY_OPTION = ["option1", "option2", "option3"]
end
m assuming payoption_type is a field in your Payoption model

Related

Rails fields_for not rendering on page

I am trying to implement a form that has associated videos when I create a new tutorial. The issue is that my form is not rendering whenever I visit the page. Could anyone help, please?
This is myapp/views/admin/tutorials/new.html.erb
<h2>New Tutorial</h2>
<%= form_for [:admin, #tutorial] do |f| %>
<%= f.label :title %>
<%= f.text_field :title, class: "block col-4 field" %>
<%= f.label :description %>
<%= f.text_area :description, class: "block col-4 field" %>
<%= f.label :thumbnail %>
<%= f.text_field :thumbnail, class: "block col-4 field" %>
<h3>Videos</h3>
<%= f.fields_for :videos do |builder| %>
<%= builder.label :youtube_url %>
<%= builder.text_field :youtube_url, class: "block col-4 field" %>
<%= builder.label :video_id %>
<%= builder.text_field :video_id, class: "block col-4 field" %>
<% end %>
<%= f.submit "Save", class: "mt2 btn btn-primary mb1 bg-teal" %>
<% end %>
This is my Video model
class Video < ApplicationRecord
has_many :user_videos
has_many :users, through: :user_videos
belongs_to :tutorial
validates_presence_of :position
end
And my Tutorial model
class Tutorial < ApplicationRecord
has_many :videos, -> { order(position: :ASC) }, dependent: :destroy
acts_as_taggable_on :tags, :tag_list
accepts_nested_attributes_for :videos
scope :without_classroom, -> { where(classroom: false) }
end
My controller:
class Admin::TutorialsController < Admin::BaseController
def new
#tutorial = Tutorial.new
end
def create
#tutorial = Tutorial.new(tutorial_params)
if #tutorial.save
flash[:success] = "Successfully created tutorial!"
redirect_to tutorial_path(#tutorial)
else
render :new
end
end
def edit
#tutorial = Tutorial.find(params[:id])
end
def update
tutorial = Tutorial.find(params[:id])
if tutorial.update(tutorial_params)
flash[:success] = "#{tutorial.title} tagged!"
end
redirect_to edit_admin_tutorial_path(tutorial)
end
private
def tutorial_params
params.require(:tutorial).permit(:tag_list, :title, :description, :thumbnail)
end
end
The reason nothing's rendered is that the videos association is empty. For example if you add #tutorial.videos.build in the new controller action, then you will get one set of the fields, and if you have multiple videos in the association (whether persisted or not) you would get one set of the fields per video.

Rails 5 trouble with saving a nested fields_for .. error message <xxx> must exist

I have the following models:
class Person < ApplicationRecord
has_many :interests, dependent: :destroy
accepts_nested_attributes_for :interests
validates_presence_of :email
validates_inclusion_of :gender, :in => %w(M F), message: "Gender can only be in M or F"
has_secure_password
def name
"#{first_name} #{last_name}"
end
def interests_concatenated
interests.map { |i| i.interest }.join(", ")
end
end
class Interest < ApplicationRecord
belongs_to :person
end
My controller is as follows:
class PeopleController < ApplicationController
def index
#person = Person.all
end
def new
#person = Person.new
#person.interests.build
end
def create
#person = Person.new(people_params)
if #person.save
session[:user_id] = #person.id
redirect_to(people_path)
else
flash = "Email or gender can't be blank!"
render 'new'
end
end
private
def people_params
params.require(:person).permit(:email, :first_name, :last_name, :gender, :password,:password_confirmation, interests_attributes: [:hobby])
end
end
My form is as follows:
<%= form_for #person do |f| %>
<p>
<%= f.label :email %> <br>
<%= f.text_field :email %>
</p>
<p>
<%= f.label :first_name %> <br>
<%= f.text_field :first_name %>
</p>
<p>
<%= f.label :last_name %> <br>
<%= f.text_field :last_name %>
</p>
<p>
<%= f.label :gender %> <br>
<%= f.label(:gender_male, "Male") %>
<%= f.radio_button(:gender, "M") %> <br>
<%= f.label(:gender_female, "Female") %>
<%= f.radio_button(:gender, "F") %> <br>
</p>
<p>
<%= f.label :password %> <br>
<%= f.password_field :password %>
</p>
<p>
<%= f.label :password_confirmation %> <br>
<%= f.password_field :password_confirmation %>
</p>
<p>
<%= f.fields_for :interests do |i| %>
<%= i.label :hobby %>
<%= i.text_field :hobby %>
<% end %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
Here is the byebug console log when I run it:
Very stumped why it's not working. Could it be something to do with the parameters?
Here is the log file when I submit the form:
Instead of:
#interests = #person.interests.new
try
#interests = #person.interests.build
new creates a fresh, clean, completely empty new object... but build is the special Rails association method that will fill it with appropriate defaults (like, eg the right person_id)
I found a working solution by adding this in my interests model:
class Interest < ApplicationRecord
belongs_to :person, **optional: true**
end
Since #person fails to save each time, the biggest clue was in the error message "Interest person must exist", I found this StackOverflow solution to be helpful. Also this blog post on why this is needed was helpful in shedding light on the issue.
Thanks to everyone that weighed in on it!

ActionController::ParameterMissing

I have made an application that has a personsController class, with an action show and new. I also created the Person model this way:
rails generate model Person name:string surname:string partner:references
The partner field should reference another person. In the new action I created a form to insert a new person into the database:
<%= form_for :person , url: persons_path do |f| %>
<p>
<%= f.label :name %>
<%= f.text_field :name %>
</p>
<p>
<%= f.label :surname %>
<%= f.text_field :surname %>
</p>
<p>
<%= f.label :partner %>
<%= f.number_field :partner , value: 0 %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
This is the personsController method create:
def create
#person= Person.new(post_params)
#Person.save
redirect_to #person
private
def post_params
params.require(:post).permit(:partner,:name,:surname);
end
The problem is that I get an error when I submit the form:
Update
I changed the instruction to:
params.require(:person).permit(:partner,:name,:surname);
But I still get an error:
NameError in PersonsController#create
uninitialized constant Person::Partner
Person model:
class Person < ActiveRecord::Base
belongs_to :partner
end
This is the problem here:
From your model post is not a defined attribute
so changed this:
def post_params
params.require(:post).permit(:partner,:name,:surname);
end
to
def post_params
params.require(:person).permit(:partner_id,:name,:surname)
end
EDIT
use partner_id instead of partner for your foreign key
<p>
<%= f.label :partner %>
<%= f.number_field :partner_id, value: 0 %>
</p>
Require person:
params.require(:person).permit(:partner, :name, :surname)

Nested form not rendering Rails 3.2

The nested form in the view just won't render, unless I remove the f attribute, in which case the submit button will not work. I have two models, job and employer. I've been following the railscast here
job.rb
attr_accessible :title, :location, :employers_attributes,
belongs_to :employers
accepts_nested_attributes_for :employers
employer.rb
attr_accessible :companyname, :url
has_many :jobs
jobs_controller.rb
def new
#job = Job.new
#employer = Employer.new
end
_form.html
<%= form_for(#job) do |f| %>
<%= f.label :title %>
<%= f.text_field :title %>
<%= f.label :location %>
<%= f.text_field :location %>
<%= f.fields_for :employers do |builder| %>
<%= builder.label :companyname, "Company Name" %>
<%= builder.text_field :companyname %>
<%= builder.label :url, "Web Address" %>
<%= builder.text_field :url %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Any input would be brilliant - thanks
This happens because your job has no employers.
Change your code to this:
def new
#job = Job.new
#job.employer = #job.build_employer
end
In your job.rb change:
attr_accessible :title, :location, :employer_attributes,
belongs_to :employer
accepts_nested_attributes_for :employer
This line:
belongs_to :employers
Should be singulars:
belongs_to :employer
With this association you not need nested form you can use select for pick employer for each job.
But if you need many employers for each job and each job can have many employers see this screencast

ActiveModel::MassAssignmentSecurity::Error with nested attributes

Hi im trying to create a relation one-to-many in my rails app.
Fist i create my models
class Produto < ActiveRecord::Base
attr_accessible :compra, :descricao, :estoque, :venda
has_many :precos
accepts_nested_attributes_for :precos
end
class Preco < ActiveRecord::Base
attr_accessible :compra_decimal, :produto_id, :venda_decimal
belongs_to :produto
end
Then i created my controller
class ProdutosController < ApplicationController
def new
#produto = Produto.new
#produto.precos.build
end
def create
#produto = Produto.new(params[:produto])
if #produto.save?
redirect_to produtos_path
end
end
end
After this i created my .html.erb pages:
_form
<%= form_for #produto do |f| %>
<p>
<%= f.label :descricao %><br/>
<%= f.text_field :descricao %>
</p>
<p>
<%= f.label :compra %><br/>
<%= f.text_field :compra %>
</p>
<p>
<%= f.label :venda %><br/>
<%= f.text_field :venda %>
</p>
<p>
<%= f.label :estoque %><br/>
<%= f.text_field :estoque %>
</p>
<%= f.fields_for :precos do |builder| %>
<%= render "precos", :f => builder %>
<% end %>
<p><%= f.submit %></p>
<% end %>
_precos
<p>
<%= f.label :venda_decimal %><br/>
<%= f.text_field :venda_decimal %>
</p>
<p>
<%= f.label :compra_decimal %><br/>
<%= f.text_field :compra_decimal %>
</p>
new
<%= render "form" %>
then, when i submit the form this error appears:
ActiveModel::MassAssignmentSecurity::Error in ProdutosController#create
Can't mass-assign protected attributes: precos_attributes
does anyone have any idea about it?
Just change your model:
class Produto < ActiveRecord::Base
attr_accessible :compra, :descricao, :estoque, :venda, :precos_attributes
has_many :precos
accepts_nested_attributes_for :precos
end

Resources