Acess nested params in view form - ruby-on-rails

I'm having trouble trying to upload images, I have a control that receives nested parameters from other models (availability, personal documents, etc ...), I made the relationships between the entities and added the "has_one_attached: img_name_example" in each model that must have an image, then I made a view with a form to be able to test the post of this form, but whenever I submit in the form I re-post the following message:
{"status":"ERROR","errors":{"disponibility":["must exist"],"personal_document":["must exist"],"personal_document_legal":["must exist"],"bank_information":["must exist"]}}
Code:
Client model:
class Client < ApplicationRecord
enum user_kind: { partner: "P", service_taker: "T" }
belongs_to :disponibility
belongs_to :personal_document
belongs_to :personal_document_legal
belongs_to :bank_information
accepts_nested_attributes_for :bank_information
accepts_nested_attributes_for :disponibility
accepts_nested_attributes_for :personal_document
accepts_nested_attributes_for :personal_document_legal
end
Client controller (require and permit):
def client_params
params.require(:client).permit(
:user_kind,
disponibility_attributes: [
:days,
:period
],
personal_document_attributes: [
:rg_front,
:rg_back,
:cpf,
:cnh_front,
:cnh_back,
:bank_card_front,
:address_proof,
:profile_picture
],
personal_document_legal_attributes: [
:cnpj,
:social_contract,
:bank_card_front
],
bank_information_attributes: [
:bank,
:account_type,
:agency,
:account_number
]
)
end
Form:
<%= form_with model: #client, local: true do |form| %>
<%= form.text_field :user_kind %> <br>
<br>
<%= form.text_field :days %> <br>
<%= form.text_field :period %> <br>
<br>
<%= form.file_field :rg_front %><br>
<%= form.file_field :rg_back %><br>
<%= form.file_field :cpf %><br>
<%= form.file_field :cnh_front %><br>
<%= form.file_field :cnh_back %><br>
<%= form.file_field :bank_card_front %><br>
<%= form.file_field :address_proof %><br>
<%= form.file_field :profile_picture %><br>
<br>
<%= form.file_field :cnpj %><br>
<%= form.file_field :social_contract %><br>
<%= form.file_field :bank_card_front %><br>
<br>
<%= form.text_field :bank %> <br>
<%= form.text_field :account_type %> <br>
<%= form.text_field :agency %> <br>
<%= form.text_field :account_number %> <br>
<br>
<%= form.submit %>
<% end %>

If I check your previous question, I think this deal how you setup your relationship between
client and other tables, if you are sure that client hold only One personal_document then
you can set as follow, if you think client can hold more than one personal document then
you have to change it to has_many
class Client < ApplicationRecord
# please note personal_document in singular
has_one :personal_document, dependent: :destroy
accepts_nested_attributes_for :personal_document, allow_destroy: :true
# now you can do some like above for disponibility, personal_document_legal, bank_information
end
class PersonalDocument < ApplicationRecord
belongs_to :client
end
class ClientsController < ApplicationController
def barang_params
params.require(:client).permit(
:user_kind,
personal_document_attributes: [
:id,
:rg_front,
:rg_back,
:cpf,
:cnh_front,
:cnh_back,
:bank_card_front,
:address_proof,
:profile_picture
]
# I think this one already correct
)
end
end
please note also since Client is parent and PersonalDocument is child
the one that relate this is field in personal_documents table that hold
client_id
check your schema here how you do migration
create_table "personal_documents", id: :serial, force: :cascade do |t|
t.integer "client_id"
# .... your other fields
end

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

Triple nested model not building correctly

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.

Rails 4: How to update a collection_select based on another collection_select through AJAX?

The problem:
I need to filter a collection of Units based upon the selection of a collection of Organizations.
Upon selecting an Organization, the Unit dropdown-menu should refresh to show only the Units that belong to informed Organization.
I've checked these questions:
Rails forms: updating collection_select options based on other collection_select value using AJAX
UJS, AJAX, Rails 4, form_for collection_select to pass value into method and return value back to form
ajax in rails with collection_select
How to add an onchange event to select tag in rails
Rails forms: updating collection_select options based on other collection_select value using AJAX
Rails form_for collection_select ignoring remote ajax call that select_tag accepts
remote select, controller needs more form data
And these documentations:
http://guides.rubyonrails.org/form_helpers.html
http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html
http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html#method-i-options_from_collection_for_select
This is my code so far:
Models
class Organization < ActiveRecord::Base
has_many :units
has_many :projects, through: :units
end
class Unit < ActiveRecord::Base
belongs_to :organization
has_many :projects
end
class Project < ActiveRecord::Base
belongs_to :organizaton
has_one :organization, through: :unit
end
Views
app/views/projects/_form.html.erb
<%= form_for(#project) do |f| %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :description %><br>
<%= f.text_area :description %>
</div>
<div class="field">
<%= f.label :organization_id %><br>
<%= f.collection_select :organization_id, Organization.all, :id, :name %>
</div>
<div class="field">
<%= f.label :unit_id %><br>
<%= f.collection_select :unit_id, Unit.all.where(organization_id: :organization_id), :id, :name %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Controllers
Projects Controller
def new
#project = Project.new
end
def project_params
params.require(:project).permit(:name, :description, :organization_id, :unit_id)
end
How can I make this work?
I made it, the solution was pretty simple, but the lack of updated material regarding this simple issue made it a chore bigger than it should have:
config/routes.rb
get 'filter_units_by_organization' => 'projects#filter_units_by_organization'
controllers/projects_controller.rb
def filter_units_by_organization
#filtered_units = Unit.where(organization_id: params[:selected_organization])
end
views/projects/filter_units_by_organization.js.erb
$('select#project_unit_id').html('<%= j options_from_collection_for_select(#filtered_units, :id, :name) %>');
assets/javascripts/application.js
$(function() {
$("select#project_organization_id").on("change", function() {
$.ajax({
url: "/filter_units_by_organization",
type: "GET",
data: { selected_organization: $("select#project_organization_id").val() }
});
});
});
views/projects/_form.html.erb
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :description %><br>
<%= f.text_area :description %>
</div>
<div class="field">
<%= f.label :organization_id %><br>
<%= f.collection_select :organization_id, Organization.all, :id, :name, { prompt: 'Please select' } %>
</div>
<div class="field">
<%= f.label :unit_id %><br>
<%= f.collection_select :unit_id, Unit.all.where(organization_id: :organization_id), :id, :name %>
</div>
<div class="actions">
<%= f.submit %>
</div>
Instead of placing an duplicate organization_id on the projects table you should set the relationship up to go through the Unit model.
class Organization < ActiveRecord::Base
has_many :units
has_many :projects, through: :units
end
class Unit < ActiveRecord::Base
belongs_to :organization
has_many :projects
end
class Project < ActiveRecord::Base
belongs_to :unit
has_one :organizaton, through: :unit
end
This avoids the awkward issue where you have to ensure that a unit and a project have the same organizaton_id.
This also means that you no longer need a input to select the organization when creating a Project - just the unit.

Auxiliary parameter in a form

I'm trying to manage invitations to an event with a "participation" model. I'd like that, when I invite a user, i could insert his name in the form, instead of user_id.
user.rb
class User < ActiveRecord::Base
attr_accessible :id, :name
has_many :participations
end
participation.rb
class Participation < ActiveRecord::Base
attr_accessible :event_id, :user_id
belongs_to :event
belongs_to :user
end
views/participations/new.html.erb
<%= form_for(#participation) do |f| %>
<%= f.hidden_field :event_id, value: #event.id %>
<%= f.label :user_id, 'User Id' %>
<%= f.number_field :user_id %>
<%= f.submit 'Invite' %>
<% end %>
How can i do?
Try by this:
<%= form_for(#participation) do |f| %>
<%= f.hidden_field :event_id, value: #event.id %>
<%= f.label :user_id, 'User Id' %>
<%=f.collection_select :user_id,User.all,:id,:name,:label => "User" ,:include_blank => false%>
<%= f.submit 'Invite' %>
<% end %>
You may turn include_blank to true or false as you wish to always have a user or not.
Feel free to ask for more if this doesn't solve your problem.

Nested form in many to many relationship in rails 4

I have a model Contact which has a many-to-many relationship with Company:
class Contact < ActiveRecord::Base has_many :contactcompanies
has_many :companies, through: :contactcompanies
Company model:
class Company < ActiveRecord::Base
has_many :contactcompanies
has_many :contacts, through: :contactcompanies
ContactCompany:
class ContactCompany < ActiveRecord::Base
belongs_to :company
belongs_to :contact
contacts_controller.rb:
def new
#contact = Contact.new
#all_companies = Company.all
#contact_company = #contact.contactcompanies.build
end
contact create form where I want to have a multiple select for companies:
<%= form_for #contact do |f| %>
<%= f.label :first_name %>
<%= f.text_field :first_name %>
<%= f.label :last_name %>
<%= f.text_field :last_name %>
<%= f.label :image_url %>
<%= f.text_field :image_url %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= fields_for(#contact_company) do |cc| %>
<%= cc.label "All Companies" %>
<%= collection_select(:companies, :id, #all_companies, :id, :name, {}, { :multiple => true }) %>
<% end %>
<div class="form-action">
<%= f.submit nil, :class => 'btn btn-primary' %>
<%= link_to t('.cancel', :default => t("helpers.links.cancel")),
contacts_path, :class => 'btn' %>
</div>
<% end %>
My issue is when I go to /contacts/new I get this error:
Circular dependency detected while autoloading constant Contactcompany
Any ideas? I'm searching for hours without success. Thanks
You have declared your class as "ContactCompany"
This implies:
has_many :contact_companies
has_many :contacts, through: :contact_companies
Without the underscore, it is looking for a class named Contactcompany, which does not exist.

Resources