Triple nested model not building correctly - ruby-on-rails

I have an Organisme that has many Servicepoints and each Servicepoint has many Addresses. The Servicepoint is set to accepts_nested_attributes_for :addresses so that I can create a service point and at the same time create an Address with it.
My problem is that that, I can't figure out how to create the address that will be linked to the Servicepoint and that Servicepoint be linked to the Organisme. I am creating the Servicepoint inside the show view of an Organisme.
View:
<%= form_for([#organisme, #organisme.servicepoints.build]) do |f| %>
<p>
<%= f.label :nom %><br>
<%= f.text_field :nom %>
</p>
<p>
<%= f.label :fax %><br>
<%= f.text_field :fax %>
</p>
<p>
<%= f.label :courriel %><br>
<%= f.email_field :courriel %>
</p>
<p>
<%= f.label :telephone %><br>
<%= f.text_field :telephone %>
</p>
<%= f.fields_for :addresses do |address_attributes| %>
<p>
<%= address_attributes.label :no_civique %><br>
<%= address_attributes.text_field :no_civique %><br>
<%= address_attributes.label :rue %><br>
<%= address_attributes.text_field :rue %><br>
<%= address_attributes.label :ville %><br>
<%= address_attributes.text_field :ville %><br>
<%= address_attributes.label :province %><br>
<%= address_attributes.text_field :province %><br>
<%= address_attributes.label :etat %><br>
<%= address_attributes.text_field :etat %><br>
<%= address_attributes.label :code_postal %><br>
<%= address_attributes.text_field :code_postal %><br>
</p>
<% end %>
<p>
<%= f.submit :Ajouter, class: 'btn btn-info' %>
</p>
<% end %>
Controller:
organisme/show
def show
#organisme = Organisme.find(params[:id])
end
servicepoint/create
def create
#organisme = Organisme.find(params[:organisme_id])
#servicepoint = #organisme.servicepoints.create(servicepoint_params)
redirect_to organisme_path(#organisme)
end
private
def servicepoint_params
params.require(:servicepoint).permit(:nom, :fax, :courriel, :telephone, addresses_attributes: [:id, :no_civique, :rue, :ville, :province, :etat, :code_postal])
end
Routes:
resources :organismes do
member { patch :activate }
member { patch :deactivate }
resources :addresses
resources :servicepoints do
resources :addresses
end
end
My problem right now is that the Address input information isn't even showing. I tried having a #servicepoint variable and then creating everything with that but the problem with that was that I could not link it to the Organisme.
If you need any more information I'll be happy to add anything.
Models:
class Organisme < ApplicationRecord
has_many :addresses
accepts_nested_attributes_for :addresses
has_many :servicepoints
end
class Servicepoint < ApplicationRecord
has_many :addresses
accepts_nested_attributes_for :addresses
belongs_to :organisme
end
class Address < ApplicationRecord
belongs_to :organismereferent, optional: true
belongs_to :organisme, optional: true
belongs_to :servicepoint, optional: true
end

I would build everything in the controller action:
<%= form_for([#organisme, #servicepoint]) do |f| %>
...
def show
#organisme = Organisme.find(params[:organisme_id])
#servicepoint = #organisme.servicepoints.build
#servicepoint.addressess.build
end

In the form you build a servicepoint, so an empty serviceform is shown as an empty form. No adress are shown because there is no address to iterate on. You need to build addresses too.
Be aware that your form will never allow you to edit servicepoint(s), because of the build in the form itself. And to allow the form to show more than one servicepoint, you need to iterate servicepoints somewhere.

Related

Changing from has_many to has_one relation rails

Here personaldetails belongs_to user and the relation given is has_many which is wrong.I want to convert the has_many relation to has_one relation i.e. User has_one personaldetails. When I change the relation directly I am getting an error "uninitialized constant User::Personaldetails. Please guide me how to convert the relation .
Personaldetail.rb
class Personaldetail < ApplicationRecord
belongs_to :user
end
User.rb
class User < ApplicationRecord
has_many :personaldetails, dependent: :destroy
accepts_nested_attributes_for :personaldetails, reject_if: :all_blank, allow_destroy: true
end
routes.rb
resources :users, except: [:new] do
resources :personaldetails
end
user_steps_controller.rb
class UserStepsController < ApplicationController
include Wicked::Wizard
steps : :personaldetails
def show
#user = current_user
#personaldetails = #user.personaldetails.build
render_wizard
end
def update
#user = current_user
#user.update!(user_params)
render_wizard #user
end
private
def user_params
params.require(:user).permit(:name, :password, :password_confirmation, :user_id,
personaldetails_attributes: [:id,:first_name, :last_name, :gmail, :mobile_no, :city, :state, :pin_code, :_destroy])
end
end
personaldetails.html.erb
<%= form_with(model: #user, url: wizard_path, local: true) do |form| %>
<%= form.fields_for :personaldetail,Personaldetail.new do |info| %>
<%= render 'personaldetails_field', form: info %>
<% end %>
<%= form.submit %>
<% end %>
_personaldetails_field.html.erb
<div class="field">
<%= form.label :First_name %><br />
<%= form.text_field :first_name %>
</div>
<div class="field">
<%= form.label :Last_name %><br />
<%= form.text_field :last_name %>
</div>
<div class="field">
<%= form.label :email %><br />
<%= form.text_field :gmail %>
</div>
<div class="field">
<%= form.label :Mobile_number %><br />
<%= form.text_field :mobile_no %>
</div>
<div class="field">
<%= form.label :City %><br />
<%= form.text_field :city %>
</div>
<div class="field">
<%= form.label :State %><br />
<%= form.text_field :state %>
</div>
<div class="field">
<%= form.label :Pincode %><br />
<%= form.text_field :pin_code %>
</div>
So the solution is:
Personaldetail.rb
class Personaldetail < ApplicationRecord
belongs_to :user
end
User.rb
class User < ApplicationRecord
has_one :personaldetails, dependent: :destroy
accepts_nested_attributes_for :personaldetails, reject_if: :all_blank, allow_destroy: true
end
routes.rb
resources :users, except: [:new] do
resources :personaldetail
end
user_steps_controller.rb
class UserStepsController < ApplicationController
include Wicked::Wizard
steps : :personaldetails
def show
#user = current_user
render_wizard
end
def update
#user = current_user
#user.update!(user_params)
render_wizard #user
end
private
def user_params
params.require(:user).permit(:name, :password, :password_confirmation, :user_id,
personaldetails_attributes: [:id,:first_name, :last_name, :gmail, :mobile_no, :city, :state, :pin_code, :_destroy])
end
end
personaldetail.html.erb
<%= form_with(model: #user, url: wizard_path, local: true) do |form| %>
<%= form.fields_for :personaldetail,#user.personaldetail || #user.build_personaldetail do |info| %>
<%= render 'personaldetail_field', form: info %>
<% end %>
<%= form.submit %>
<% end %>
_personaldetail_field.html.erb
<div class="field">
<%= form.label :First_name %><br />
<%= form.text_field :first_name %>
</div>
<div class="field">
<%= form.label :Last_name %><br />
<%= form.text_field :last_name %>
</div>
<div class="field">
<%= form.label :email %><br />
<%= form.text_field :gmail %>
</div>
<div class="field">
<%= form.label :Mobile_number %><br />
<%= form.text_field :mobile_no %>
</div>
<div class="field">
<%= form.label :City %><br />
<%= form.text_field :city %>
</div>
<div class="field">
<%= form.label :State %><br />
<%= form.text_field :state %>
</div>
<div class="field">
<%= form.label :Pincode %><br />
<%= form.text_field :pin_code %>
</div>
try with: has_one :personaldetail, dependent: :destroy
Rails are guessing class name from name AND type of association, so with has_many they will try to singularize association name (personaldetails => Personaldetail) but with has_one they will try to reach it as is (personaldetails => Personaldetails)
As in the comment by spickermann, has_many relationship wants plural form and has_one the singular form.
That is to say, you should already be able to infer the relationship from:
#user.personaldetails # user has many personal details
#user.personaldetail # user has one personal detail
Just a consideration: many weird cases arise when objects/models are not properly named. As a rule of thumb, you should use the most fitting and precise English noun for the object you need to name. That will help you hugely in cases like this. In normal English language, it is somehow strange to say "a user has a personal detail" but you would say of course "has personal details". Particularly when it comes to ActiveRecord associations, Rails syntax should be the nearest as possible to English language, to avoid later misunderstandings. I guess this confusion would not have arisen if instead of "PersonalDetail", the model was called "Account" or "Profile", for instance.
Few suggestions/comments
Keep model name as CamelCase like PersonalDetail rather than Personaldetail and association name has_one :personal_detail
Using has_one relation you can create the object using user.build_personal_detail.save
When you run the 2nd step again it will create another record in personal_details table and in that transaction it will return the new record. But, after that when you try to query it will return the 1st created personal_details record rather than new one. That's because ActiveRecord by default sorts by id and limit 1 for has_one relation

Nested form fields for associated STI model

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

Rails 4: fields_for in fields_for

I am learning RoR and i am trying to find how to set a fields_for in another one with has_one models like this:
class Child < ActiveRecord::Base
belongs_to :father
accepts_nested_attributes_for :father
end
class Father < ActiveRecord::Base
has_one :child
belongs_to :grandfather
accepts_nested_attributes_for :grandfather
end
class Grandfather < ActiveRecord::Base
has_one :father
end
I used Nested Model Form Part 1 on Railscasts to get these:
In children_controller.rb:
def new
#child = Child.new
father=#child.build_father
father.build_grandfather
end
def child_params
params.require(:child).permit(:name, father_attributes:[:name], grandfather_attributes:[:name])
end
And my form:
<%= form_for(#child) do |f| %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
mother:<br>
<%= f.fields_for :father do |ff| %>
<%= ff.label :name %>
<%= ff.text_field :name %><br>
grand mother:<br>
<%= f.fields_for :grandfather do |fff| %>
<%= fff.label :name %>
<%= fff.text_field :name %>
<% end %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
I am trying to retrieve the datas with:
<%= child.father.name %>
<%= child.father.grandfather.name %>
but the grandfather's name won't work.
I cannot find the mistake(s)...anyone to help on this?
Thanks!
Try switching:
<%= f.fields_for :grandfather do |fff| %>
to:
<%= ff.fields_for :grandfather do |fff| %>
And switching:
params.require(:child).permit(:name, father_attributes:[:name], grandfather_attributes:[:name])
To:
params.require(:child).permit(:name, father_attributes:[:name, grandfather_attributes:[:name]])

Rails 4 oracle enhanced adapter many to many propagating data to the pivot table

First things first
Using:
rails4
oracle enhanced adapter rails4 branch
I have a many to many relationship mapped on an existing database.
My models look as such:
class EventMap < ActiveRecord::Base
self.table_name="TAKE_PART"
self.primary_key="id"
belongs_to :event, foreign_key: "lottery_event_id"
belongs_to :entrant, foreign_key: "address_id"
end
class Event < ActiveRecord::Base
self.table_name="THE_EVENT"
self.primary_key="id"
has_many :event_maps, :foreign_key => "lottery_event_id"
has_many :entrants, :through => :event_maps
accepts_nested_attributes_for :entrants, :reject_if => :all_blank
end
class Entrant < ActiveRecord::Base
self.table_name="ADDRESSES"
self.primary_key="id"
self.set_date_columns :date_of_birth
has_many :events, :through => :event_maps
has_many :event_maps, :foreign_key => "address_id"
end
static page controller for my voting page
...
def vote
#event=Event.find_by(id: 4227)
#entrants=#event.entrants
#entrant=#event.entrants.build
end
...
vote view:
<%= form_for(#event) do |f| %>
<%= f.fields_for :entrant do |builder| %>
<%= render "/entrants/fields", :f => builder %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
entrant/fields partial:
<% if #entrant.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#entrant.errors.count, "error") %> prohibited this entrant from being saved:</h2>
<ul>
<% #entrant.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.hidden_field :id %>
<div class="field">
<%= f.label :lastname %><br>
<%= f.text_field :lastname %>
</div>
<div class="field">
<%= f.label :firstname %><br>
<%= f.text_field :firstname %>
</div>
<div class="field">
<%= f.label :street %><br>
<%= f.text_field :street %>
</div>
<div class="field">
<%= f.label :country_id %><br>
<%= f.number_field :country_id %>
</div>
<div class="field">
<%= f.label :city %><br>
<%= f.text_field :city %>
</div>
<div class="field">
<%= f.label :telephone %><br>
<%= f.text_field :telephone %>
</div>
<div class="field">
<%= f.label :email %><br>
<%= f.text_field :email %>
</div>
<div class="field">
<%= f.label :date_of_birth %><br>
<%= f.date_select :date_of_birth %>
</div>
<div class="field">
<%= f.label :lang_id %><br>
<%= f.text_field :lang_id %>
</div>
<div class="field">
<%= f.label :added %><br>
<%= f.date_select :added %>
</div>
<div class="field">
<%= f.label :salut %><br>
<%= f.text_field :salut %>
</div>
<div class="field">
<%= f.label :zip %><br>
<%= f.text_field :zip %>
</div>
<div class="field">
<%= f.label :newsletter %><br>
<%= f.check_box :newsletter %>
</div>
<div class="field">
<%= f.label :company %><br>
<%= f.text_field :company %>
</div>
The form now submits to event controller PATCH
class EventsController < ApplicationController
before_action :set_event, only: [:show, :edit, :update, :destroy]
...
# PATCH/PUT /events/1
# --> HOW DO I SAVE THE SUBMITTED ENTRANT HERE??? <--
def update
respond_to do |format|
if #event.update(event_params)
format.html { redirect_to #event, notice: 'Event was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #event.errors, status: :unprocessable_entity }
end
end
end
...
private
# Use callbacks to share common setup or constraints between actions.
def set_event
#event = Event.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def event_params
params.require(:event).permit(:id, :lottery_id, :events_dates_id, :event_date, :event_location, :tickets_for_winner, :prize, :tickets_internally,
:entrants_attributes => [:id, :lastname, :firstname, :street, :country_id, :city, :telephone, :email, :date_of_birth, :lang_id, :added, :salut, :zip, :newsletter, :company])
end
end
How do I register an Entrant with an Event, adding data only to the intermediate model EventMap since the Event will always exist?
Do I need to include accepts_nested_attributes_for in my models to propagate changes accross tables (I could not quite figure out what this does from the documentation)? Do I need to send additional params via the Entrant form to update the EventMap?
Main GOAL: I want a form where Entrants can register to an existing event!
Hard to judge about Your forms, as we don't see any ;)
But You are right to be able to create nested attributes, from nested attributes from, You need to set accepts_nested_attributes_for :some_model, :some_other_model
If You find docs confusing, consult Railscasts:
http://railscasts.com/episodes/196-nested-model-form-part-1
http://railscasts.com/episodes/197-nested-model-form-part-2
You are requiring custom logic and that custom logic must be defined, Rails will not automatically update everything, it must be defined in the update controller as you suggest.
I might do something along the lines of this:
def update
entrant = Entrant.find(params[:entrant_id])
event = Event.find(params[:event_id])
EventMap.create!(event: event, entrant: entrant)
#.... go on with usual stuff
# Alternatively you could use build
event_map = EventMap.new
event_map.build(event: event, entrant: entrant)
end

Rails way to set up relationship for this model

Being new at Ruby and Rails, I wasn't sure how to explain this in my title so i will do it here. My goal is to create many Products and with those have only one overall Location per submit.
I have a Product MVC and a quick ugly sketch of the form would be something like this:
Overall Location
form_for #product
<p>
<%= f.label :location %>:<br>
<%= f.text_field :location %>
</p>
Product one
<p>
<%= f.label :name %>:<br>
<%= f.text_field :name %>
<%= f.label :price %>:<br>
<%= f.text_field :price %>
</p>
Product Two (same)
<p>
<%= f.label :name %>:<br>
<%= f.text_field :name %>
<%= f.label :price %>:<br>
<%= f.text_field :price %>
</p>
Product Three(same)
<p>
<%= f.label :name %>:<br>
<%= f.text_field :name %>
<%= f.label :price %>:<br>
<%= f.text_field :price %>
</p>
<%= f.submit %>
<% end %>
How would you set it up so this relationship could take place so when a user creates 3 products on a form, he has only one location for all 3 of them?
This way:
class Location < AR::Base
has_many :products
end
class Product < AR::Base
belongs_to :location
end
You'd then set up a nested resource route:
resources :locations do
resources :products
end
And when you're adding a location, you can add products to it with fields_for.
is it required to use nested_attributes_for in this scenario..

Resources