Rails enum not saving to database from select options - ruby-on-rails

this is my tables looks like:
class Promo < ActiveRecord::Base {
:id => :integer,
:product_id => :integer,
:promo_code => :string,
:name => :string,
:description => :text,
:user_id => :string,
:email => :string,
:status => :integer,
:category => :integer,
:expire_date => :date,
:user_limit => :integer,
:created_at => :datetime,
:updated_at => :datetime
}
ane here is my model:
class Promo < ActiveRecord::Base
enum category: [ :discount, :rebate, :custom]
enum status: [ :offered, :claimed, :redeemed ]
end
and my view:
<%= f.select :category, options_for_select(Promo.categories.map { |w| w }, #promo.category) %>
which will generate html like this:
<select name="promo[category]" id="promo_category">
<option value="0">discount</option>
<option value="1">rebate</option>
<option value="2">custom</option>
</select>
But when I try to save it, it throw an error which says:
'0' is not a valid category
How to save enum to database? thanks
UPDATE
I have found the link before.
I change it my view like this:
<%= f.select :category, options_for_select(Promo.categories.keys.to_a.map { |w| [w.humanize, w] }, #promo.category) %>
but back to my root problems, its not working, it says that :
ActiveRecord::RecordNotSaved: Failed to save the record
from /home/krismp/.rvm/gems/ruby-2.1.5/gems/activerecord-4.2.3/lib/active_record/persistence.rb:142:in `save!'
why this is happen?

The value submitted by this form snippet won’t validate because update is expecting the “string” key, and not the underlying numerical value of the table.
Instead, you can use following:
<%= f.select :category, options_for_select(Promo.categories.map {|k,v| [k,k]}) %>
or
<%= f.select :category, options_for_select(Promo.categories.map {|k,v| [k,k]}, #promo.category) %>

Related

Unpermitted parameter simple_form

I am trying to create a nested form with Simple_fields in ruby 4.
However, every time i try to enter data into the form I get a unpermitted parameter error in the server console after trying to submit.
I already tried the solutions found in the simple_form wiki and did some testing, but that doesn't seem to work.
The _form:
<%= simple_form_for(#enquiry) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<H1>Algemene informatie</H1>
<%= f.input :reference, placeholder: 'Referentie' %>
<br>
<%= f.label :Locatie %>
<%= f.select :location, [['Chemiepark', 'chemiepark'], ['Farmsum', 'farmsum'], ['Winschoten', 'winschoten']] %>
<br>
<%= f.input :description, placeholder: 'Omschrijving' %>
<br>
<%= f.input :date %>
<br>
<%= f.input :amount, placeholder: 'Aantal' %>
</div>
<hr>
<% if false %>
<div class="form-inputs">
<%= f.simple_fields_for :enquiry_measures do |e| %>
<H1>Maatregelen</H1>
<%= e.input :responsible, placeholder: 'Verantwoordelijke' %>
<br>
<%# e.input :needed, as: :check_boxes,
collection: ["ja", "nee"] %>
<% end %>
<br>
</div>
<% end %>
<div class="form-inputs">
<%= f.simple_fields_for :tools do |t| %>
<% #enquiry.tools.each do |tool| %>
<%= field_set_tag 'Tool' do %>
<%= f.simple_fields_for "tool_attributes[]", tool do |tf| %>
<h1>Gereedschappen</h1>
<br>
<%= tf.input :handtool, placeholder: 'Handgereedschap' %>
<% end %>
<% end %>
<% end %>
<% end %>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
The strong attributes plus what i tested:
def enquiry_params
# was gegenereerd door de scaffold params.fetch(:enquiry, {})
params.require(:enquiry).permit(:reference, :location, :description, :date, :amount,
:enquiry_measures_attributes => [:done, :responsible, :needed], :tools_attributes => [:handtool] )
#:enquiry_measures_attributes => [:done, :responsible, :needed])
#enquiry_measure_attributes: [:done, :responsible, :needed] )
update
code from models
class Enquiry < ActiveRecord::Base
#ophalen van andere tabellen voor het formulier. Has_many is 1 op veel relatie
#accepts_nested_attributes Nested attributes allow you to save attributes on associated records through the paren
# de dere regel zorgt ervoor dat de maatregelen worden opgehaald via de tussentabel enquiry_measures.
has_many :enquiry_measures, :class_name => 'EnquiryMeasure' #, inverse_of: :Enquiry
accepts_nested_attributes_for :enquiry_measures, :allow_destroy => true
has_many :measures, -> { uniq }, :class_name => 'Measure', :through => :enquiry_measures, dependent: :destroy
accepts_nested_attributes_for :measures, :allow_destroy => false
has_many :controls, :class_name => 'Control' #, inverse_of: :Enquiry
has_many :applicants, :class_name => 'Applicant' #, inverse_of: :Enquiry
has_many :agrees, :class_name => 'Agree' #, inverse_of: :Enquiry
has_many :signatures, :class_name => 'Signature' #, inverse_of: :Enquiry
accepts_nested_attributes_for :signatures, :allow_destroy => false
has_many :tools, :class_name => 'Tool', :dependent => :destroy #, inverse_of: :Enquiry
accepts_nested_attributes_for :tools, :allow_destroy => true
#:dependent => :destroy zorgt ervoor dat de foreign record ook word verwijderd.
#de instances van andere tabellen:
e = Enquiry.new
e.enquiry_measures.build(:enquiry_id => :id)
e.measures.build
# 28-11 MG de pagina's die in het form worden gebruikt.
cattr_accessor :form_steps do
%w(basic when measurements tool)
end
attr_accessor :form_step
validates :reference, presence: true, if: -> { required_for_step?(:basic) }
validates :amount, :date, presence: true, if: -> { required_for_step?(:when) }
#validates :needed, presence: true, if: -> { required_for_step?(:measurements) }
def required_for_step?(step)
return true if form_step.nil?
return true if self.form_steps.index(step.to_s) <= self.form_steps.index(form_step)
end
#voor het mailen met behulp van de mailgem:
# Declare the e-mail headers. It accepts anything the mail method
# in ActionMailer accepts.
def headers
{
:subject => "My Contact Form",
:to => "marco.groenhof#jpbgroep.nl",
:from => %("#{name}" <#{email}>)
}
end
end
and 1 of the related models: in this case enquiry_measure
class EnquiryMeasure < ActiveRecord::Base
belongs_to :enquiry
validates_presence_of :enquiry
has_many :measure
#serialize zodat de data uit de collection select met multiple: true op kan worden geslagen.
serialize :measure
end
and tools:
class Tool < ActiveRecord::Base
belongs_to :enquiry, :class_name => 'Enquiry' #, inverse_of: :applicant
validates_presence_of :enquiry
end
I know class_name is not really needed anymore.
UPDATE
The logging:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"i3YukMoOaYEuUdxk6kmhoQ5q9uLQHHISW+NAU/L+kNjSwMZERmdIIVXZvJUh0vTnEPidaMvMEIlVT/aTlkTNPw==", "enquiry"=>{"reference"=>"Test", "location"=>"chemiepark", "description"=>"3ro0qjhrojeofj", "date(1i)"=>"2017", "date(2i)"=>"1", "date(3i)"=>"3", "amount"=>"2", "tools_attributes"=>{"0"=>{"handtool"=>"Hamer"}}}, "commit"=>"Create Enquiry"}
The only weird thing i see is the "tools_attributes"=>{"0"=>{"handtool"=>"Hamer"}}}
Why is that 0 there? Could it be the id, because that would make sense to why i can not save.
And just to make sure, this is the tool tabel and foreign key:
add_index "tools", ["enquiry_id"], name: "index_tools_on_enquiry_id", using: :btree
create_table "users", force: :cascade do |t|
t.string "name", limit: 255
t.string "email", limit: 255
t.string "password_digest", limit: 255
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_foreign_key "tools", "enquiries"
UPDATE 4/01
Just installed rails panel to see what that would say, but i keep thinking the problem is within the parameters:
{"reference":"test","location":"chemiepark","description":"iwopjf","date(1i)":"2017","date(2i)":"1","date(3i)":"4","amount":"2","tools_attributes":{"0":{"handtool":"hamer"}}}
Why does it keep sending that 0? i suspect it to be the tool id, which would declare the not being able to save.
Try making you strong parameter as
params.require(:enquiry).permit(:reference, :location, :description, :date, :amount, enquiry_measures_attributes: [:id, :done, :responsible, :needed, :_destroy], tools_attributes: [:id, :handtool, :_destroy] )
And your model that is being nested should be something as below. Try doing this once.
class Tool < ActiveRecord::Base
# For a while let's not have any validation.
end
Hope this will work in your case as I fix it for my own.
I decided to updatew this question as i got the answer that helped me. It may not be the completely correct answer, but i managed to solve my issue by using the default form_for in uby on Rails. A bit more coding work, but it does work.

validate_uniqueness_of scope not working

Currently I can create one item with multiple designs in unique picturelocs. Creating a second item gives me the following error that there already exists a pictureloc with that value, even though it is in a seperate item_id and shouldn't be worried over. This is my first question so cut me some slack on the formatting, and thanks in advance!
Error:
PG::Error: ERROR: duplicate key value violates unique constraint "index_designs_on_pictureloc"
DETAIL: Key (pictureloc)=(1) already exists.
: INSERT INTO "designs" ("created_at", "item_id", "picture_content_type", "picture_file_name", "picture_file_size", "picture_updated_at", "pictureloc", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING "id"
Design.rb
class Design < ActiveRecord::Base
attr_accessible :picture, :pictureloc
has_attached_file :picture, styles: {medium: "150x150#"}
validates_attachment :picture, presence: true,
content_type: { content_type: ['image/jpeg', 'image/jpg', 'image/png'], :message => 'must be a PNG, JPG, or JPEG'},
size: {less_than: 5.megabytes, :message => 'must be less than 5 megabytes'}
validates_uniqueness_of :pictureloc, scope: :item_id
belongs_to :item
def show_location
if pictureloc == 1
"Front"
elsif pictureloc == 2
"Back"
elsif pictureloc == 3
"Left Sleeve"
elsif pictureloc == 4
"Right Sleeve"
end
end
end
Item.rb
class Item < ActiveRecord::Base
attr_accessible :price, :make, :amount, :color, :note, :designs_attributes
validates_presence_of :make, :amount, :color
validates :amount, :numericality => { :greater_than => 0 }
belongs_to :quote
has_many :designs, :dependent => :destroy
accepts_nested_attributes_for :designs
end
Index in the schema:
add_index "designs", ["pictureloc"], :name => "index_designs_on_pictureloc", :unique => true
nested item view:
<!-- item form -->
<%= f.input :make, collection: #types, label: 'Thread Type' %>
<%= f.input :amount, label: 'How Many' %>
<%= f.input :color, collection: #colors %>
<!-- nested form for creating a design of an item -->
<%= f.simple_fields_for :designs, :html => { :multipart => true } do |designform| %>
<%= render "customdesign", g: designform %>
<% end %>
<!-- add/remove another design -->
<%= f.link_to_add "Add Design", :designs %>
<%= f.input :note, :input_html => { :cols => 50, :rows => 3 }, label: 'Special Notes or Requests' %>
<%= f.link_to_remove "Remove" %>
Nested design view:
<!-- upload/remove image form -->
<%= g.select( :pictureloc, { "Front" => 1, "Back" => 2, "Left Sleeve" => 3, "Right Sleeve" => 4 } ) %>
<%= g.file_field :picture %>
<%= g.link_to_remove "Remove" %>
Note that pictureloc is an integer, and that the designs get saved at the same time which is why I had to create an index (I think?)
I tried removing the unique: true from the index because maybe it was overkill, but that didn't solve anything.
Your index should be
add_index "designs", ["pictureloc", "item_id"], :name => "index_designs_on_pictureloc", :unique => tru

yet another Can't mass-assign protected attributes: address post

Preface: I am trying to create a customer for that has a nested addresses form. upon clicking create customer i get this error.
ActiveModel::MassAssignmentSecurity::Error in Admin::CustomersController#create
Can't mass-assign protected attributes: address
customer model
class Customer < ActiveRecord::Base
attr_accessible :name, :email, :phone, :addresses_attributes
has_many :addresses
accepts_nested_attributes_for :addresses, :allow_destroy => true
end
address model
class Address < ActiveRecord::Base
attr_accessible :street, :city, :state, :zip, :customer_id
belongs_to :customer
has_one :customer_id
end
Customers controller
ActiveAdmin.register Customer, :sort_order => "name_asc" do
# Menu item
menu :label => "Customers", :parent => "Administration"
filter :name
filter :created_at
filter :updated_at
action_item :only => [:show] do
link_to "Contacts", client_contacts_path( resource )
end
index do |t|
selectable_column
column(:name, sortable: :name) { |customer| link_to truncate(customer.name, length: 35), customer, title: customer.name }
column "Created", :sortable => :created_at do |customer|
customer.created_at.humanize
end
column "Updated", :sortable => :updated_at do |customer|
customer.updated_at.humanize
end
column "" do |customer|
restricted_default_actions_for_resource(customer) + link_to( "Contacts", client_contacts_path(customer), :class => "member_link" )
end
end
form :partial => "form"
show :title => :name do
panel "Customer Details" do
attributes_table_for resource do
row :name
row :email
row :phone
row :created_at do
resource.created_at.humanize
end
row :updated_at do
resource.updated_at.humanize
end
end
text_node(render :partial => "admin/addresses/show", :locals => { :address => resource.address })
end
end
end
To say i have tried everything is a lie because it won't work, though i have tried to get this to work for a while.
You must add
accepts_nested_attributes_for :addresses
in your Customer model.
By the way, why the error is in singular (Address and not Addresses)?
You must add :addresses_attributes to the attr_accessible call too.

Rails nested form with has_many :through, not saving the data to joining table

I am kinda new to Rails and this is my first post to StackOverflow.
Say I have 3 models:
class Product < ActiveRecord::Base
default_scope :order => :title
has_many :line_items
has_many :promo_products
has_many :promotions, :through => :promo_products, :foreign_key => :promotion_id
before_destroy :ensure_not_referenced_by_any_line_item
before_destroy :ensure_not_referenced_by_any_promo_product
validates :title, :presence => true, :uniqueness => true
validates :description, :presence => true
validates :price, :numericality => {:greater_than_or_equal_to => 0.01}
private
def ensure_not_referenced_by_any_line_item
if line_items.empty?
return true
else
errors.add(:base, 'Line Items present')
return false
end
end
def ensure_not_referenced_by_any_promo_product
if promo_products.empty?
return true
else
errors.add(:base, 'Some promotions are still in effect')
return false
end
end
end
class Promotion < ActiveRecord::Base
CART_OR_PRODUCT = ['Cart', 'Product']
PROMOTION_TYPE = ['Percentage based', 'Value based']
has_many :promo_products
accepts_nested_attributes_for :promo_products
has_many :products, :through => :promo_products, :foreign_key => :product_id
accepts_nested_attributes_for :products
#attr_accessible :promo_products_attributes, :title, :description, :cart_or_product, :promotion_type, :discount, :minimum_price, :minimum_quantity
validates :title, :description, :presence => true
validates :cart_or_product, :inclusion => {:in => CART_OR_PRODUCT, :message =>
"is invlaid. Please select a valid option"}
validates :promotion_type, :inclusion => {:in => PROMOTION_TYPE, :message =>
"is invalid. Please select a valid option"}
validates :discount, :minimum_price, :numericality => {:greater_than_or_equal_to => 0.00}
validates :minimum_quantity, :numericality => {:greater_than_or_equal_to => 0}
end
class PromoProduct < ActiveRecord::Base
belongs_to :promotion
belongs_to :product
accepts_nested_attributes_for :products
end
In the promotions new page, I would like to show list of products that could be part of a promotion. A user may select 0, 1 or more products, depending on the type of promotion.
In the action new of promotions_controller, I built like this:
#promotion.promo_products.build.build_product
In the _form of promotions, I needed to show the list of products for user to select. I made a nested form like:
<%= form_for(#promotion) do |f| %>
<!-- other promotion fields -->
<%= f.fields_for :promo_products do |pp| %>
<%= pp.fields_for :products do |p| %>
<div class="field">
<%= f.label "Products" %><br />
<%= collection_select :promo_product, :product_id, Product.all, :id, :title {:selected => #promotion.product_ids}, {:multiple => true} %>
</div>
<% end %>
<% end %>
<% end %>
I have 2 issues.
First my code throws an error:
ArgumentError in PromotionsController#new
No association found for name `products'. Has it been defined yet?
If I change the line in PromoProduct model:
accepts_nested_attributes_for :products
to
accepts_nested_attributes_for :product
Then there are no errors, and everything works fine.
The data doesn't get saved to promo_product table. I have the create action in promo_product controller as:
def create
#promotion = current_promotion
products = Product.select(:id => params[:product_id])
products.each do |p|
promo_product = #promotion.promo_products.build(p)
promo_product.save
end
##promo_product = PromoProduct.new(params[:promo_product])
redirect_to promotions_path
end
How can I go about it?
Thank you.
You shouldn't put the "accept_nested_attribute_for" in the association table PromoProducts. It should exist in the model that you want to use for creating association to another model. "accept_nested_attribute_for" IIRC simply inserts an "[association]_attributes=" method for your model. For instance, if you add this method to your Product class for Promotion, you will get "promotion_attributes=" method inserted in the Product class. Then a nested form can use this function to create new objects with a hash that represents the model and association.
Base on the above, the create action shouldn't be in PromoProduct controller, instead it should be in Promotion controller.
<%= form_for(#promotion) do |f| %>
<!-- other promotion fields -->
<%= f.fields_for :products do |pp| %>
<div class="field">
<%= f.label "Products" %><br />
<%= collection_select :promo_product, :product_id, Product.all, :id, :title {:selected => #promotion.product_ids}, {:multiple => true} %>
</div>
<% end %>
<% end %>
I don't know without trying if the above collection_select line is correct. But you can debug this by checking the parameter returned by the form to the controller in the server console log. Basically you should see a nested hash of
{:promotion => {:products => ...}}
Let me know if you need more help on this. In my solution I used a combination of select_tag and options_from_collection_for_select. (But I don't recall the behavior of all these offhand without looking at the API doc.)
Lastly, do you need the :through model? I think since you created the through model you need to handle saving that in your create action. But since you don't have other attributes on the PromoProducts table I wonder if you want to simply leave it as a HABTM association and let rails deal with the rest?

rails3-jquery-autocomplete reference id with formtastic

I just started my Rails app and I have the following problem - I want to use the jQuery UI and autocomplete, and therefore have used the gem rails3-jquery-autocomplete. I also use formtastic for my rails forms.
I have two models:
Customer:
class Customer < ActiveRecord::Base
has_many :carts
end
create_table :customer do |t|
t.column :lastname, :string
t.column :forename, :string
end
Cart:
class Cart < ActiveRecord::Base
belongs_to :customer
end
create_table :cart do |t|
t.column :costumer_id, :integer
end
As explained in the doc of the gem I made the autocomplete config in my CartController:autocomplete :customer, :lastname, :full => true
In my view with the formtastic code it looks like this:
<%= semantic_form_for #cart do |f| %>
<%= f.inputs do %>
<%= f.input :customer,
:as => :autocomplete,
:url => autocomplete_customer_lastname_carts_path,
:id_element => '#cart_customer_id' %>
The main question that I have is, how to deal with the id stuff. I mean, I want to store the reference id of the customer in my cart model and not the name itself. I recognized the possibility to take the :id_element option to reference an id input field for storing the id in the form. I figured out, that there seems to be a problem with the formtastic combination, and found a potential solution.
I could do this, with an <%= f.input :customer_id, :as => :hidden %>, but I really don't know what to write in the line: <%= f.input :customer, :as => :autocom.... Is :customer the right solution for this? This approach would give me the following: "cart"=>{"customer"=>"26","customer_id"=>"0"}
Does anyone have an idea, possibly I totally misunderstand the whole :id_element thing...
You also got a wrong column name into your migration.
create_table :cart do |t|
t.column :customer_id, :integer
end
ok i found it :)
so you need to make an hidden_field with customer_id and tell to autocomplete to update this input value. the tag :update_elements => {}
<%= autocomplete_field_tag "cart_customer_name", "" , autocomplete_customer_lastname_carts_path, :id_element => "#customer_customer_id", :update_elements => {} %><br />
<%= f.hidden_field :customer_id %>
So :id_element is the id element you want to update when a result is selected.

Resources