When i try to submit the form below i get this error WARNING: Can't mass-assign protected attributes: sub_category.I have tried to go over previous asked related questions here on stackoverflow and seems like i am in the right track ,but for some reason i am still getting the same error,what am i doing wrong?.I have included all the info below, thank you in advance.
View/form
<%= form_for #ip ,:url=>{:action =>"create"} do |f| %>
<%=f.text_field :email %>
<% f.text_field :ip_address %>
<%= f.fields_for :sub_category do |s| %>
<%=s.text_field :name%>
<%end%>
<%=f.submit "submit" %>
<%end%>
Controller
def create
#ips=Ip.new(params[:ip])
#ip=#ips.sub_categories.build
if #ip.save
redirect_to :controller=>"home" ,:action=>"index"
else
render 'index'
end
Models
class Ip < ActiveRecord::Base
has_many :sub_categories ,:through=>:ip_subs
has_many :ip_subs
accepts_nested_attributes_for :sub_categories
attr_accessible :sub_categories_attributes,:ip_address,:email,:ip_count
end
class SubCategory < ActiveRecord::Base
has_many :ip ,:through=>:ip_subs
has_many :ip_subs
end
class IpSub < ActiveRecord::Base
belongs_to :ip
belongs_to :sub_category
end
You should use f.fields_for :sub_categories (association name).
And don't forget to build association before render the form:
# in controller
def new
#ip = Ip.new
#ip.sub_categories.build
end
rubyonrails api :: fields_for
Related
any help would be most appreciated, I am rather new to Rails.
I have two models a Shopping List and a Product. I'd like to save/update multiple products to a shopping list at a time.
The suggested changes are not updating the models. I've been googling and is "attr_accessor" or find_or_create_by the answer(s)?
Attempt 1 - Existing code
Error
> unknown attribute 'products_attributes' for Product.
Request
Parameters:
{"_method"=>"patch",
"authenticity_token"=>"3BgTQth38d5ykd3EHiuV1hkUqBZaTmedaJai3p9AR1N2bPlHraVANaxxe5lQYaVcWNoydA3Hb3ooMZxx15YnOQ==",
"list"=>
{"products_attributes"=>
{"0"=>{"title"=>"ten", "id"=>"12"},
"1"=>{"title"=>"two", "id"=>"13"},
"2"=>{"title"=>"three", "id"=>"14"},
"3"=>{"title"=>"four", "id"=>"15"},
"4"=>{"title"=>"five", "id"=>"16"},
"5"=>{"title"=>""},
"6"=>{"title"=>""},
"7"=>{"title"=>""},
"8"=>{"title"=>""},
"9"=>{"title"=>""},
"10"=>{"title"=>""}}},
"commit"=>"Save Products",
"id"=>"7"}
Attempt 2 - no errors the page reloads and none of the expected fields are updated. In earnest, I am Googling around and copying and pasting code snippets in the vain hope of unlocking the right combo.
Added to Products mode
class Product < ApplicationRecord
attr_accessor :products_attributes
belongs_to :list, optional: true
end
<%= content_tag(:h1, 'Add Products To This List') %>
<%= form_for(#list) do |f| %>
<%= f.fields_for :products do |pf| %>
<%= pf.text_field :title %><br>
<% end %>
<p>
<%= submit_tag "Save Products" %>
</p>
<% end %>
<%= link_to "Back To List", lists_path %>
list controller
def update
#render plain: params[:list].inspect
#list = List.find(params[:id])
if #list.products.update(params.require(:list).permit(:id, products_attributes: [:id, :title]))
redirect_to list_path(#list)
else
render 'show'
end
list model
class List < ApplicationRecord
has_many :products
accepts_nested_attributes_for :products
end
original do nothing - product model
class Product < ApplicationRecord
belongs_to :list, optional: true
end
If you just want a user to be able to select products and place them on a list you want a many to many association:
class List < ApplicationRecord
has_many :list_items
has_many :products, through: :list_products
end
class ListItem < ApplicationRecord
belongs_to :list
belongs_to :product
end
class Product < ApplicationRecord
has_many :list_items
has_many :lists, through: :list_products
end
This avoids creating vast numbers of duplicates on the products table and is known as normalization.
You can then select existing products by simply using a select:
<%= form_for(#list) do |f| %>
<%= f.label :product_ids %>
<%= f.collection_select(:product_ids, Product.all, :name, :id) %>
# ...
<% end %>
Note that this has nothing to with nested routes or nested attributes. Its just a select that uses the product_ids setter that's created by the association. This form will still submit to /lists or /lists/:id
You can whitelist an array of ids by:
def list_params
params.require(:list)
.permit(:foo, :bar, product_ids: [])
end
To add create/update/delete a bunch of nested records in one form you can use accepts_nested_attributes_for together with fields_for:
class List < ApplicationRecord
has_many :list_items
has_many :products, through: :list_products
accepts_nested_attributes_for :products
end
<%= form_for(#list) do |f| %>
<%= form.fields_for :products do |pf| %>
<%= pf.label :title %><br>
<%= pf.text_field :title %>
<% end %>
# ...
<% end %>
Of course fields_for won't show anything if you don't seed the association with records. That's where that loop that you completely misplaced comes in.
class ListsController < ApplicationController
# ...
def new
#list = List.new
5.times { #list.products.new } # seeds the form
end
def edit
#list = List.find(params[:id])
5.times { #list.products.new } # seeds the form
end
# ...
def update
#list = List.find(params[:id])
if #list.update(list_params)
redirect_to #list
else
render :new
end
end
private
def list_params
params.require(:list)
.permit(
:foo, :bar,
product_ids: [],
products_attrbutes: [ :title ]
)
end
end
Required reading:
Rails Guides: Nested forms
ActiveRecord::NestedAttributes
fields_for
I'm kinda new to ruby on rails, I've been reading documentation on assosiations and I've been having an easy time (and usually a quick google search solves most of my doubts) however recently I'm having problems with a seemingly easy thing to do.
What I'm trying to do is to create an Event, linked to an existing Category.
Event model
class Event < ApplicationRecord
has_many :categorizations
has_many :categories, through: :categorizations
accepts_nested_attributes_for :categorizations
.
.
.
end
Category model
class Category < ApplicationRecord
has_many :categorizations
has_many :events, through: :categorizations
end
Categorization model
class Categorization < ApplicationRecord
belongs_to :event
belongs_to :category
end
Event controller
class EventsController < ApplicationController
def new
#event = Event.new
end
def create
#user = User.find(current_user.id)
#event = #user.events.create(event_params)
if #event.save
redirect_to root_path
else
redirect_to root_path
end
end
private
def event_params
params.require(:event).permit(:name, category_ids:[])
end
Here is the form, which is where I think the problem lies:
<%= form_for #event, :html => {:multipart => true} do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.fields_for :categorizations do |categories_fields|%>
<% categories = [] %>
<% Category.all.each do |category| %>
<% categories << category.name %>
<% end %>
<%= categories_fields.label :category_id, "Category" %>
<%= categories_fields.select ( :category_id, categories) %>
<% end %>
.
.
.
<%= f.submit "Create"%>
<% end %>
I previously populate the Category db with some categories, so what's left to do is to while creating an event, also create a categorization that is linked both to the new event and the chosen Categorization. but the things I've tried don't seem to be working.
Other things seem to be working ok, whenever I try to submit the event all things are populated as expected except the categorization.
As you mentioned that you are new to rails, you'll find this cocoon gem very interesting. You can achieve what you wanted. And the code will cleaner.
I don't have the points to comment, that's why I am giving this as an answer.
I'm creating an application where a "submission" can be made using a form which creates client details and allows "referrals" to be created depending on the branch(es) that can provide the required service
class Submission < ActiveRecord::Base
has_many :referrals, :inverse_of => :submission, dependent: :delete_all
accepts_nested_attributes_for :referrals, :allow_destroy => true
end
class Referral < ActiveRecord::Base
belongs_to :submission
end
class Branch < ActiveRecord::Base
has_many :referrals
end
Submissions controller:
def new
#submission = Submission.new
#submission.build_client
#submission.client.build_address
#submission.referrals.build
end
def submission_params
params.require(:submission).permit(:consent, :user_id, client_attributes:
[:client_id, :first_name,
address_attributes:
[:first_line, :second_line,]
],
referrals_attributes:
[:branch_id]
)
end
The Submission form:
<%= form_for(#submission) do |f| %>
<%= f.fields_for :referrals do |referral| %>
<%= render 'referral_fields', f: referral %>
<% end %>
<% end %>
_referral_fields.html.erb:
<% Branch.all.where(referrable: true).each do |branch| %>
<label>
<%= check_box_tag 'branch_ids[]', branch.id %>
<%= branch.name %>
</label>
<% end %>
What I want is to have checkboxes for each referrable branch. When a branch is ticked and the submission is created, a referral will be created for that branch. However, when I submit the form, I get a validation error of "Referrals can't be blank". Any idea why this is not working?
Any help is most appreciated
Use collection_check_boxes.
<% # _referral_fields.html.erb %>
<%= f.collection_check_boxes(:branch_ids, Branch.where(referrable: true), :id, :name) do |b|
b.label { b.check_box } # wraps check box in label
end %>
You would need to whitelist submission[referrals_attributes][branch_ids] - not branch_id.
def submission_params
params.require(:submission)
.permit(
:consent,
:user_id,
client_attributes: [
:client_id,
:first_name,
address_attributes: [
:first_line, :second_line,
]
],
referrals_attributes: [:branch_ids]
)
end
Edited.
However for this to work you need to setup a relation between Referral and Branch. In this case you could use either a has_and_belongs_to_many (HABTM) or has_many though: (HMT) relationship.
See Choosing Between has_many :through and has_and_belongs_to_many.
class Referral < ActiveRecord::Base
belongs_to :submission
has_and_belongs_to_many :branches
end
class Branch < ActiveRecord::Base
has_and_belongs_to_many :referrals
end
You need to create a join table as well:
rails g migration CreateBranchReferralJoinTable branch referral
I'm trying to associate a relation betwen 1 patient with a consultation, but I'm getting a error:
Association :patient not found
In the model I have:
class Patient < ActiveRecord::Base
belongs_to :user
has_many :consultums, through: :patients
end
class Consultum < ActiveRecord::Base
belongs_to :patients
belongs_to :user
has_one :recetum
end
in the controller I have:
class ConsultationController < ApplicationController
before_action :authenticate_user!
before_action :set_consultum, only: [:show, :edit, :update, :destroy]
respond_to :html
def index
#consultation = Consultum.all
respond_with(#consultation)
end
def show
respond_with(#consultum)
end
## when I try to create a new consultation, throw me the error ##
def new
#consultum = Consultum.new
# patient_id
respond_with(#consultum)
end
def edit
end
def create
#consultum = Consultum.new(consultum_params)
#consultum.save
respond_with(#consultum)
end
def update
#consultum.update(consultum_params)
respond_with(#consultum)
end
def destroy
#consultum.destroy
respond_with(#consultum)
end
# def patient_id
# patient = Patient.find(params[:id])
# # patient = #patient.id
# #consultum.patient_id = patient
# end
private
def set_consultum
#consultum = Consultum.find(params[:id])
end
def consultum_params
params.require(:consultum).permit(:Reason_Consultation, :Diagnostic, :TX, :Labs, :Observations, :patient_id)
end
end
so, as you can see I create the function patient_id, and I'm trying to retrieve the id from the 'patient' and put into patient_id in 'consultum' table, but seems not work...
if I uncomment patient_id function throw me this error:
Couldn't find Patient without an ID
I'm stuck, any idea?
Thanks in advance
EDIT
in my view I have:
consultation/new.html.erb
<div class="page-header">
<%= link_to consultation_path, class: 'btn btn-default' do %>
<span class="glyphicon glyphicon-list-alt"></span>
Back
<% end %>
<h1>New consultum</h1>
</div>
<%= render 'form' %>
_form.html.erb
<%= simple_form_for(#consultum) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :Reason_Consultation %>
<%= f.input :Diagnostic %>
<%= f.input :TX, placeholder: "optional" %>
<%= f.input :Labs, placeholder: "optional" %>
<%= f.input :Observations, placeholder: "optional" %>
<%= f.association :patient %>
</div>
<div class="form-actions">
<%= f.button :submit, "Save Consultation" %>
</div>
<% end %>
When creating associations in rails pay super close attention to the pluralization!
class Patient < ActiveRecord::Base
belongs_to :user
has_many :consultums, through: :patients
end
class Consultum < ActiveRecord::Base
belongs_to :patients
belongs_to :user
has_one :recetum
end
You will notice that your Consultum class does not have a patient relation. It has belongs_to :patients.
class Consultum < ActiveRecord::Base
belongs_to :patient
belongs_to :user
has_one :recetum
end
Also your attribute naming should follow the Ruby conventions!
Ruby uses snake_case for naming attributes and methods and will automatically treat any identifier which begins with an UPPERCASE letter as a constant!
This is not just a stylistic issue - MRI Ruby will let you reassign constants with a warning. Other versions or future versions may be less lenient.
Bad Good
.Reason_Consultation .reason_consultation
.Diagnostic .diagnostic
.TX .tx
.Lab .lab
.Observations .observations
https://github.com/bbatsov/ruby-style-guide
To call an action you can pass parameters as follow:
link_to "New Consultum", new_consultum_path(:id => here, yo have to put the paciente id)
Hope this helps!
Currently, an Item belongs_to a Company and has_many ItemVariants.
I'm trying to use nested fields_for to add ItemVariant fields through the Item form, however using :item_variants does not display the form. It is only displayed when I use the singular.
I have check my associations and they seem to be correct, could it possibly have something to do with item being nested under Company, or am I missing something else?
Thanks in advance.
Note: Irrelevant code has been omitted from the snippets below.
EDIT: Don't know if this is relevant, but I'm using CanCan for Authentication.
routes.rb
resources :companies do
resources :items
end
item.rb
class Item < ActiveRecord::Base
attr_accessible :name, :sku, :item_type, :comments, :item_variants_attributes
# Associations
#-----------------------------------------------------------------------
belongs_to :company
belongs_to :item_type
has_many :item_variants
accepts_nested_attributes_for :item_variants, allow_destroy: true
end
item_variant.rb
class ItemVariant < ActiveRecord::Base
attr_accessible :item_id, :location_id
# Associations
#-----------------------------------------------------------------------
belongs_to :item
end
item/new.html.erb
<%= form_for [#company, #item] do |f| %>
...
...
<%= f.fields_for :item_variants do |builder| %>
<fieldset>
<%= builder.label :location_id %>
<%= builder.collection_select :location_id, #company.locations.order(:name), :id, :name, :include_blank => true %>
</fieldset>
<% end %>
...
...
<% end %>
You should prepopulate #item.item_variants with some data:
def new # in the ItemController
...
#item = Item.new
3.times { #item.item_variants.build }
...
end
Source: http://rubysource.com/complex-rails-forms-with-nested-attributes/
try this way
in your item controller new action write
def new
...
#item = # define item here
#item.item_variants.build if #item.item_variants.nil?
...
end
and in item/new.html.erb
<%= form_for #item do |f| %>
...
...
<%= f.fields_for :item_variants do |builder| %>
...
<% end %>
...
...
<% end %>
for more see video - Nested Model Form