I'm using simple_form, and I just want to create association between categories and articles using categorization table.
But I have this error:
Can't mass-assign protected attributes: category_ids.
app/controllers/articles_controller.rb:36:in `update'
articles_controller.rb
def update
#article = Article.find(params[:id])
if #article.update_attributes(params[:article]) ---line with the problem
flash[:success] = "Статья обновлена"
redirect_to #article
else
render :edit
end
end
article.rb
has_many :categorizations
has_many :categories, through: :categorizations
category.rb
has_many :categorizations
has_many :articles, through: :categorizations
categorization.rb
belongs_to :article
belongs_to :category
categorization has article_id and category_id fields.
My _form.html.erb
<%= simple_form_for #article, html: { class: "form-horizontal", multipart: true } do |f| %>
<%= f.error_notification %>
<%= f.input :title %>
<%= f.association :categories %>
<%= f.input :teaser %>
<%= f.input :body %>
<%= f.input :published %>
<% if #article.published? %>
<%= f.button :submit, value: "Внести изменения" %>
<% else %>
<%= f.button :submit, value: "Опубликовать" %>
<% end %>
<% end %>
do you have attr_accessible in article.rb?
if so add
attr_accessible :title, :category_ids
Also make sure you really want this for all forms... If not add this:
attr_accessible :title, :category_ids, :as => :admin
then
#article = Article.new
#article.assign_attributes({ :category_ids => [1,2], :title => 'hello' })
#article.category_ids # => []
#article.title # => 'hello'
#article.assign_attributes({ :category_ids => [1,2], :title => 'hello' }, :as => :admin)
#article.category_ids # => [1,2]
#article.title # => 'hello'
#article.save
or
#article = Article.new({ :category_ids => [1,2], :title => 'hello' })
#article.category_ids # => []
#article.title # => 'hello'
#article = Article.new({ :category_ids => [1,2], :title => 'hello' }, :as => :admin)
#article.category_ids # => [1,2]
#article.title # => 'hello'
#article.save
The form field created by
<%= f.association :categories %>
is going to set the attribute category_id, but the attribute is protected. In you model you should have a line of code looks like this:
attr_accessible :title, :teaser, :body, :published
these attributes are allowed for mass assignment. If you want the form to set category_id you have to add these attribute to the attr_accessible method:
attr_accessible :title, :teaser, :body, :published, :category_id
This should fix your issue.
Related
Using check boxes to update the nested form I can't update the tables. I received following message:
Unpermitted parameter: :category
ActionController::Parameters
{"name"=>"Flux Capacitor", "price"=>"19.55"} permitted: true
I have tried different ways to fix this through the permitted params, including a :category parameter, like so:
def product_params
params.require(:product).permit(:id, :name, :price, :category, categories_attributes: [:id, :name, :category], categorizations_attributes: [:id, :product_id, :category_ids, :category])
end
My models
class Product < ApplicationRecord
has_many :categorizations
has_many :categories, through: :categorizations
accepts_nested_attributes_for :categories, reject_if: proc {|attributes| attributes['name'].blank?}
accepts_nested_attributes_for :categorizations
end
class Categorization < ApplicationRecord
belongs_to :product, inverse_of: :categorizations
belongs_to :category, inverse_of: :categorizations
end
class Category < ApplicationRecord
has_many :categorizations
has_many :products, through: :categorizations, inverse_of: :category
end
class ProductsController < ApplicationController
def edit
#categories = Category.all
end
def new
#product = Product.new
end
def create
#product = Product.new(product_params)
if #product.save
flash[:notice] = 'Product succesfully created'
redirect_to products_path
else
flash[:notice] = 'Product was not created'
render 'edit'
end
end
def update
if #product.update(product_params)
flash[:notice] = "Product succesfully updated"
redirect_to products_path
else
flash[:notice] = 'Product was not updated'
render 'edit'
end
end
app/view/products/edit.html.erb
<%= simple_form_for(#product) do |f| %>
<%= f.input :name %>
<%= f.input :price %>
<%= f.simple_fields_for #product.categories do |cats| %>
<%= cats.collection_check_boxes :ids, Category.all, :id, :name, collection_wrapper_tag: :ul, item_wrapper_tag: :li %>
<% end %>
<%= f.button :submit %>
<% end %>
This seems like something that is common enough that rails and/or simple_form, should provide in a more built-in way to do this. Am I missing something obvious?
If I am understanding you correctly you should be able to do this without the use of accepts_nested_attributes_for or simple_fields_for. Try something like this:
<%= simple_form_for(#product) do |f| %>
<%= f.input :name %>
<%= f.input :price %>
<%= f.association :categories, as: :check_boxes %>
<%= f.button :submit %>
<% end %>
your strong params should look something like this:
def product_params
params.require(:product).permit(:id, :name, :price, { category_ids: [] }])
end
I have 3 models; Quote, Item, and Product.
My quote/new.html.erb is set up to render a partial which contains the item form, and in that item form a partial is rendered to choose a product.
the error: ActiveModel::MassAssignmentSecurity::Error in QuotesController#create
"Can't mass-assign protected attributes: products"
(I edited out irrelevant stuff in the following)
Quote.rb
class Quote < ActiveRecord::Base
attr_accessible :items_attributes
has_many :items, :dependent => :destroy
accepts_nested_attributes_for :items
end
Item.rb
class Item < ActiveRecord::Base
attr_accessible :price, :product_attributes
belongs_to :quote
belongs_to :product
accepts_nested_attributes_for :product
end
Product.rb
class Product < ActiveRecord::Base
attr_accessible :name, :item_make
has_many :items
accepts_nested_attributes_for :items
end
new.html.erb
<%= simple_nested_form_for #quote do |m| %>
<%= m.simple_fields_for :items, :html => { :multipart => true } do |quoteform| %>
<%= render "form", f: quoteform %>
<% end %>
<%= m.link_to_add "Add an item", :items %>
<%= m.button :submit %>
<% end %>
_form.html.erb
<%= f.simple_fields_for :products, :html => { :multipart => true } do |x| %>
<% render "layouts/styleselect", g: x %>
<% end %>
_styleselect.html.erb
<% g.hidden_field :item_make, :value => #item.make %>
<%= g.input :name, collection: Product.where(:item_make => 1), label: false, input_html: {:id=>"sst_style"} %>
So basically the nested form goes Quote->Item->Product, but item belongs to product, which maybe is causing the problem? I tried adding product_attributes or products_attributes to both the item model and the quote model, and the same with accepts_nested_attributes_for product(s).
Any help would be appreciated, thanks.
Looks like you need to make products singular.
<%= f.simple_fields_for :product, :html => { :multipart => true } do |x| %>
<% render "layouts/styleselect", g: x %>
<% end %>
You currently have:
<%= f.simple_fields_for :products, :html => { :multipart => true } do |x| %>
I have nested resources
resources :invoices do
resources :payments
end
The invoices model is as follows:
class Invoice < ActiveRecord::Base
belongs_to :customer, :inverse_of => :invoices
attr_accessible :due_date, :invoice_date, :reading_ids, :customer_id, :customer, :status, :amount, :balance
has_many :invoice_items, :dependent => :destroy
has_many :payments, :dependent => :destroy
end
The payments model is as follows:
class Payment < ActiveRecord::Base
attr_accessible :amount, :method, :payment_date, :reference_no, :invoice_id
belongs_to :invoice
end
The payments controller is as follows:
class PaymentsController < ApplicationController
before_filter :authenticate_user!
def new
invoice = Invoice.find(params[:invoice_id])
#payment = invoice.payments.build
respond_to do |format|
format.html #new.html.erb
end
end
end
I have created a view to record new payments and would like to display the customer details (name in particular) in this view, how do i go about it?
Payments view
<%= simple_form_for [#payment.invoice, #payment], :html => { :class => 'form-horizontal' } do |f| %>
<%= render "shared/error_messages", :target => #payment %>
<h5> Invoice Details </h5>
<%= f.input :invoice_id, disabled: true, as: :string %>
<%= f.input :method, as: :select, :collection => [['Cash','Cash'],['Cheque','Cheque'],['In-House transfer','In-House transfer'],['Account Ledger','Account ledger']], :selected => ['Cash','Cash'] %>
<%= f.input :reference_no, as: :string %>
<%= f.input :payment_date, as: :string, input_html: { class: "datepicker" } %>
<% end %>
Just use:
<%= #payment.invoice.customer.name %>
anywhere in the view.
When creating an appointment, for let say Organization 'ABC', I can also see physicians that belongs to other organization. It suppose to only list physician from 'ABC' and not others. How should I go about this.
Thank you.
My Appointment form:
<%= simple_form_for(#appointment, :html => { :class => 'form-horizontal' }) do |f| %>
<div class="form-inputs">
<%= f.hidden_field :patient_id %>
<%= f.association :physician, :label_method => :first_name, :include_blank => false, :as => :radio_buttons, :required => true %>
<%= f.hidden_field :appointment_date, :value => DateTime.now %>
<%= f.hidden_field :organization_id, :value => current_user.organization_id%>
</div>
<div class="form-actions">
<%= f.button :submit, "Create Appointment" %>
</div>
<% end %>
My models:
/app/models/physician.rb
class Physician < ActiveRecord::Base
has_many :appointments
has_many :patients, :through => :appointments
belongs_to :organization
attr_accessible :physician_name, :organization_id
end
/app/models/appointment.rb
class Appointment < ActiveRecord::Base
belongs_to :physician
belongs_to :patient
belongs_to :organization
attr_accessible :physician_id, :patient_id, :appointment_date, :state, :organization_id
end
/app/models/patient.rb
class Patient < ActiveRecord::Base
has_many :appointments
has_many :physicians, :through => :appointments
belongs_to :organization
attr_accessible :patient_name, :organization_id
end
My Controllers:
/app/controllers/appointment_controller.rb
class AppointmentsController < ApplicationController
def new
#appointment = Appointment.new
#appointment.patient_id = params[:patient_id]
end
def create
#appointment = Appointment.new(params[:appointment])
if #appointment.save
flash[:notice] = "New appointment record created"
redirect_to dashboards_path
else
render 'new'
end
end
end
This is because simple_form does not know about your scopes. If you tell it:
<%= f.association :phyisician %>
it will simply list all available physicians in the database.
The solution is to give it the collection of physicians you want to show, for example you could write:
<%= f.association :physician,
:collection => #appointment.patient.organization.physicians,
:label_method => :first_name,
:include_blank => false,
:as => :radio_buttons,
:required => true %>
I am new to rails and using a combination of formtastic, activeadmin,sti and polymorphic associations to build a form
When I I can create a nested form with the address parent with no problem, but when i introduce STI and attempt to build_origin_address instead of build_address, that is when I get the error below when loading the edit view
NameError in Admin/leads#edit
Showing .../app/views/admin/leads/_form.erb where line #3 raised:
uninitialized constant Lead::OriginAddress
Models:
class Address < ActiveRecord::Base
belongs_to :addressable, :polymorphic => true
belongs_to :lead
validates :line1, :presence => true, :length => {:minimum => 2}
attr_accessible :line1, :line2, :city, :state, :zip, :country
end
class OriginAddress < Address
end
class DestinationAddress < Address
end
class Lead < ActiveRecord::Base
has_one :origin_address, :dependent => :destroy, :as => :addressable
accepts_nested_attributes_for :origin_address, :allow_destroy => true
end
partial used in edit view:
<%= semantic_form_for [:admin, #lead] do |f| %>
<% #lead.build_origin_address unless #lead.origin_address %>
<%= f.inputs :name => "Lead Info" do %>
<%= f.input :first_name %>
<%= f.input :last_name %>
<% end %>
<%= f.semantic_fields_for :origin_address do |origin| %>
<%= origin.inputs :name => "Origin Address" do %>
<%= origin.input :line1 %>
....
<% end %>
<% end %>
<%= f.buttons do %>
<%= f.commit_button %>
<% end %>
<% end %>
I think you must define #lead before your form.