rails not receive array value strong parameter - ruby-on-rails

I had a problem that it didn't received array value when i tried to submit array value which i used checkbox.
Here is my code:
This is migration file:
create_table :users do |t|
t.string :email, null: false, default: ""
t.string :encrypted_password, null: false, default: ""
t.text :receive_mail, array: true, default: []
...
This is function which i put array attributes:
def configure_sign_up_params
devise_parameter_sanitizer.permit(:sign_up, keys: [
:address,
{receive_mail: []}
])
end
This is view file:
<div class="field">
<%= f.collection_check_boxes(:receive_mail, [[0, "receive new article"], [1, "receive new ebook"]], :first, :last, include_hidden: false) do |b| %>
<%= b.label {b.check_box + b.text} %>
<% end %>
</div>
When i submit, i checked params and it had a value as "receive_mail"=>["0", "1"], but when i checked when it permited, it always return "receive_mail"=>[].
I didn't understand why it didn't receive value.
Any help would be great appreciated.

I think your issue stems from your use of the keys option, which appears to only accept a list of symbols. You could try using:
devise_parameter_sanitizer.permit(:sign_up, keys: [
:address,
:receive_mail
])
However, I think you'll run into the following issue, mentioned in the Devise docs:
If you have some checkboxes that express the roles a user may take on registration, the browser will send those selected checkboxes as an array. An array is not one of Strong Parameters' permitted scalars, so we need to configure Devise in the following way ...
Given that, here's a variant of your code based on the example from the docs that might work:
devise_parameter_sanitizer.permit(:sign_up) do |user_params|
user_params.permit({receive_mail: []}, :address)
end

Related

Rails 5.2 | Select2 Multiple Comma Seperated Parameter

I'm new to Rails and I'm running in circles trying to implement a Select2 input with multiple selections. I've read the solutions on StackOverflow and none of them helped me, which typically means I'm doing something unusually wrong.
When I'm submitting my form it sends my federation_list parameter multiple times with different values (in headers):
event[federation_list]: WDC
event[federation_list]: WDSF
I need all of the values in one Federation parameter seperated by a comma, that I can then split in my controller.
I've tried adding name: "federation_list[]" as it says in the Select2 documentation, but my form_with overwrites it so it loses the brackets.
Updated! I figured out the solution and this is my working code:
select2_initializer.js
$( document ).on('turbolinks:load', function() {
$( "#event_federation_list" ).select2({
theme: "bootstrap",
multiple: true,
placeholder: 'Select Federation(s)',
width: 'style'
}).val('').trigger('change');
});
_form.html.erb
<div class="form-group">
<%= form.label :federation_list, value: "Federations", class: "form-label" %>
<%= form.select :federation_list, options_from_collection_for_select(Federation.all, :id, :name, {:selected => #event.federations.map(&:id)}), {}, { multiple: true } %>
</div>
The :selected makes the selected options appear when the user edits the form.
event.rb
def federation_list
self.federations.map(&:name).join(', ')
end
def federation_list=(names)
self.federations = names.split(',').map do |n|
Federation.where(name: n.strip).first_or_create!
end
end
If it is relevant information my Event has_many: Federations, through: Event_Federations.
GitHub rep
I ended up going with Selectize instead of Select2, but the solution still holds true for Select2.
And then I wrote this piece of code in my event.rb:
def federation_list
self.federations.map(&:name).join(', ')
end
def federation_list=(ids)
self.federations = ids.reject!(&:empty?).map do |id|
Federation.where(id: id).first
# Use .first_or_create! to let the user add new objects
end
end
I used SteveTurczyns advise and added federation_list: [] in my strong params.
And that works!
not sure if this is your only problem but a definite problem is that strong parameters require that you explicitly specify if a model parameter is an array.
Instead of
params.require(:event).permit(:title, :country,
:city, :start_date, :end_date, :published_at, :user_id,
:federation_list)
You should have
params.require(:event).permit(:title, :country,
:city, :start_date, :end_date, :published_at, :user_id,
federation_list: [])

Rails select from database

Can somebody explain this ? , it is from ruby guides
<%= collection_select(:person, :city_id, City.all, :id, :name) %>
I have an attachment model, I want to select its version with combobox when I create an object, and also I want a new version option.
here what attachment has
def change
create_table :attachments do |t|
t.string :filename
t.attachment :file
t.string :version
t.text :description
t.timestamps null: false
end
UPDATE:
<%= f.collection_select( :version, Attachment.where.not(version: nil), :version, :version) %>
it is working like that, but I don't understand,
Try this to avoid the nil value of the version:
collection_select(:f, :attachment_id, Attachment.where.not(version: nil), :id, :version)
Explanation of How collection_select Works:
collection_select(
:f, # field namespace
:attachment_id, # field name
# result of these two params will be: <select name="f[attachment_id]">...
# then you should specify some collection or array of rows.
# In your example it is:
Attachment.where.not(version: nil)
# Then, you should specify methods for generating options
:id, # this is name of method that will be called for every row, result will be set as key
:version # this is name of method that will be called for every row, result will be set as value
)
See this and this for more information.
check accepted answer from this thread for explanation on how collection_select works: Can someone explain collection_select to me in clear, simple terms?
In this select:
<%= collection_select(:f, :attachment_id, Attachment.all, :id, :version) %>
you display all versions from already created attachments, so if attachments table is empty you will get null

validates :terms, acceptance: true not showing error

In my model I have the following validator:
validates :terms, acceptance: true, on: :create, allow_nil: false
attr_accessor :terms
and in my form I have:
= simple_form_for #reservation do |f|
= f.error_notification
= f.input :terms, as: :boolean
The problem is that when user not accept the terms it not showing any error, why?
Try this:
validates :terms, :acceptance => {:accept => true} , on: :create, allow_nil: false
Problem may have terms as an actual column in the table. In general validates_acceptance_of is used without such a column, in which case it defines an attribute accessor and uses that for its validation.
In order for validates_acceptance_of to work when it maps to a real table column it is necessary to pass the :accept option, like:
validates :terms, :acceptance => {:accept => true} , :on => :create , allow_nil: false
The reason for this has to do with typecasting in Active Record. When the named attribute actually exists, AR performs typecasting based on the database column type. In most cases the acceptance column will be defined as a boolean and so model_object.terms will return true or false.
When there's no such column attr_accessor :terms simply returns the value passed in to the model object from the params hash which will normally be "1" from a checkbox.
Via noodl
I may have had a similar problem (Rails 4.2.0). I created a checkbox, but it would be ignored and never report and error if unchecked. I found that adding the parameter to the .permit part of my Strong Parameters allowed it to be present.
In my view template for my _form I have something like this:
<div class="field">
<%= label_tag :tos, 'I accepts the TOS' %><br>
<%= f.check_box :tos %>
</div>
I generated my model using scaffold, so my create method start like this
def create
#thing = Thing.new(thing_params)
then near the bottom I have the following for thing_params
def thing_params
params.require(:thing).permit(:field1, :field2, :tos)
end
in my model I used the following:
validates_acceptance_of :tos
If I leave out ':toslike thisparams.require(:thing).permit(:field1, :field2) it will not pop up an error and allows it to continue. This seems counter-intuitive because if Strong Parameters is removing the :tos field then I would think the validate_acceptance would fail.
I had initially just create a checkbox without using f.check_box. Now, if I even try to call the new route without :tos" being listed as permitted, rails throws an error. There also seems to be some rails magic going on because if I remove the validates_acceptance_of from my model, I receive an NoMethodError error when rendering my view saying undefined methodtos'` for the line
<%= f.check_box :tos %>
Would be great if someone else could explain what exactly is going on as I just hacked this together from googling and guessing.

Why do I get the error "undefined method 'merge' for true:TrueCLass" when adding a checkbox in Rails

I am very new to development and was hoping someone could assist:
I receive the error "undefined method 'merge' error when I include the following checkbox:
<%= f.check_box :is_female, true %> <%= f.label :is_female, "Female" %>
<%= f.check_box :is_female, false %> <%= f.label :is_female, "Male" %>
The above code is in the profiles folder which I created using the following:
$ rails generate scaffold profiles description:string
I then generated the following migration:
$ rails generate migration add_websites_to_profiles website:string
This created the migrate file *************_add_website_to_profiles.rb
Here is the add_websites_to_profiles.rb:
class AddWebsiteToProfiles < ActiveRecord::Migration
def change
add_column :profiles, :website, :string
add_column :profiles, :is_female, :boolean, default: false
end
end
I manually added the following:
add_column :profiles, :is_female, :boolean, default: false
I receive the error when I have the true and false command in the checkbox. When I remove true false it appears on the page with no error, but it is not saved to db.
You are getting mixed up between two ways of generating a check box I think.
The form builder version, f.check_box, you are using expects a hash as the second parameter. You'd need to call f.check_box(:is_female, {}, true) for a value of true.
check_box_tag on the other hand does expect a value as the second parameter. You could use check_box_tag(:is_female, true) instead.
However, as #Santosh points out in the comments, you'd probably be better off having a pair of radio buttons if you want the object to be either male or female.

Rails 4: Accept year as string and store as date

In my Rails 4 app, I'd like to accept a year as a string in a text field but store it as a date in the database, in case I ever decide to accept full dates. However, when I try to do this, I keep getting a nil date value. I've verified that the controller is properly passing along the parameters to the model, but at some point before the validation happens, the date has been set to nil.
Is what I'm trying to do possible? And if so, what critical step have I missed? Thanks!
This is the relevant part of the form:
<p>
<%= f.label :publication_date %><br>
<%= f.text_field :publication_date, :size => 4 %>
</p>
And the schema:
create_table "books", force: true do |t|
t.string "title"
t.datetime "created_at"
t.datetime "updated_at"
t.date "publication_date"
...
end
And the model validation:
validates :publication_date, length: { is: 4 }, numericality: true
before_validation :check_pub_date
def check_pub_date
# this prints nil
logger.debug "Publication date: #{self.publication_date}"
end
before_save :convert_pub_year
def convert_pub_year
# Never gets here because validation never passes
logger.debug "Publication year: #{self.publication_date}"
if self.publication_date
self.publication_date = DateTime.strptime(self.publication_date, "%Y")
end
end
Given that your model is expecting a full date to come through, you are hitting a problem when you are passing only a string from your form - I would create a simple text_field to capture the year and go from there...
In your view
<%= text_field_tag :pub_year %>
In your controller
publication_year = params[:pub_year]
#book.publication_date = DateTime.strptime(publication_year, "%Y")
or, of course, factor the parsing of year into a full date into the model.
Edit - expanding on this, it's also possible to create a property in your model that doesn't get saved to the database if you prefer, so in your model, you would have this:
attr_accessor :pub_year
Then, in your convert_pub_year, substitute in pub_year instead of publication_date
def convert_pub_year
if self.pub_year
self.publication_date = DateTime.strptime(self.pub_year, "%Y")
end
end
You controller would need to allow the pub_year parameter in addition to any others you want - so in the private methods - something like the following:
def book_params
params.require(:book).permit(:title, :pub_year)
end
And finally in your view, remove publication_date' and includepub_year`:
<%= f.label :pub_year %><br>
<%= f.text_field :pub_year %>
Hope that helps
The problem exists because validation occurs AFTER assignment of the string passed from the controller, i.e. what you are validating is not the string but the attribute after the type cast to a date. If this fails (because - as in your case - the date is incomplete and consists only of a year), the attribute is nil.
For situations like yours you might want to look into the attribute_before_type_cast functions/variables which will give you access to the original date string BEFORE it was type cast into nil.

Resources