Scaffold and Array type column - ruby-on-rails

I have created model, controller and view with rails scaffold generator:
rails g scaffold Todo description:string tags:array
So I have the model:
class Todo
include Mongoid::Document
field :description, :type => String
field :tags, :type => Array
end
And controller:
def create
#todo = Todo.new(params[:todo])
#todo.save
But this case (auto-generated code) I get error that tells me something like:
tags field must be array datatype, but you're trying to use string
So I have fixed the controller:
def create
##todo = Todo.new(params[:todo])
#tmp = params[:todo]
#tmp["tags"] = #tmp["tags"].split(',')
#todo = Todo.new(#tmp)
And I'm just wondering if there is any better way to fix my error?

Depends on how your view is structured. From what I see, there must be a single text input or something, into which you input tags, separated by comma. No wonder it comes as a string! In this case your workaround is correct. I would add stripping of leading and trailing whitespace, though.
#tmp["tags"] = #tmp["tags"].split(',').map(&:strip)
To get a real array in params your HTML must look like this:
<input type='text' name='tags[]' />
<input type='text' name='tags[]' />
<input type='text' name='tags[]' />
Where each of these inputs holds a single tag.

Related

Rails 5: How to handle serialized string array in simple_form?

As title, I have a serialized string column in the model:
class Product < ApplicationRecord
serialize :ingredient_fields, Array
end
The ingrdient_field has many strings, but store in one column within the product model. It is not nested objects.
But I'm not sure how to handle these dynamic text inputs use simple_form, or if I can use cocoon or nested_form_fields to handle the behaviors. I tried many different ways with these gems to generate the html like:
<form>
<input name="product[ingredient_fields][]"> <button>remove</button>
<input name="product[ingredient_fields][]"> <button>remove</button>
<button>add ingredient</button>
</form>
but all failed.
Or I can only write html and js myself?
you can insert index into input names, for example:
<input name="product[ingredient_fields][1]">
<input name="product[ingredient_fields][2]">
so rails will receive an array of products[ingredient_fields]

How to Store the text fields array data in database without using loop using rails

I am new in ror and I am trying from 4 hours to store the data of form of textfields array like this
<input type="text" name="custom_field[names][]" class="form-control full-width" placeholder = "Name">
<input type="text" name="custom_field[length_limit][]" class="form-control full-width" placeholder = "Length Limit">
I want to store the arrays coming into the form in database columns of name and length limit. I don't want to use loop to do this job.
I am doing this in controller
user = CustomField.create(:name=> params[:names])
But it is giving ERROR: null value in column "name" violates not-null constraint DETAI
params are
{"names"=>["tester", "another tester"], "length_limit"=>["aaaaaa222", "aaaaaa222"]
I am using postgresql
How can I do this?
params[:names] is an array, so it doesn't make sense to save it to a string/text field in postgres, which is what CustomField.create(:name=> params[:names]) does.
Essentially, it expands to CustomField.create(:name=> ["tester", "another tester"]). If you want to create a separate CustomField record for each name, then you could do something like:
params[:names].each do |name|
CustomField.create(:name => name)
end
To create the CustomField records with the corresponding length_limit, you could do something like:
params[:names].zip(params[:length_limit]).each do |name, limit|
CustomField.create(:name => name, :length_limit => limit)
end
Note that this doesn't account for errors where the names and length_limits don't match. You might want to add some validation to make sure that all the required data is present.

How to wrap incoming params with a specific attribute in rails?

if I have a manually created html form with the following input field
<input type="text" name="email">
it gives the following params {"email" => "123" }
How can I wrap it with message_fields without specifying it inside the form?
eg without the following
<input type="text" name="message_fields[:email]">
So I just want to wrap my params with message_fields from my controller.
controller strong params
params.permit(:comment, message_fields: {})
The idea is to assign all incoming params to message_fields
which is t.hstore "message_fields"
"message_fields"=>{":email"=>"qew"}"
had to do the following but there definitely should be something better
fields = #mailbox.allowed_fields.gsub(" ", "").split(",")
h = {}
fields.each do |f|
h[f] = params[f]
end
attrs = message_params.tap do |p|
p["message_fields"] = h
end
then I just pass attr to create meth insted of message_params.

undefined method `map' for "1,2":String

I need to pass an array in a params, possible? Values can be, for example, ["1","2","3","4","5"] and these are strings but needs to eb converted to integers later.
I use a react_component in between a rails form_for. The html is like this:
<input type="hidden" name="people_id" id="people_id" value={this.state.people} />
The people array looks like this:
How can I pass the array in the value of the hidden field? The server error I got was
Im trying to do something like this in a model:
ids = params[:people_id]
ids.map do |b|
Foo.create!(people_id: b.to_i)
end
If I ids.split(",").map I get symbol to int error.
Edit:
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
Still not sure what the issue is as nothing works. Here is a minimal reproduction of my code:
This answer is my react component and that's how I add to the array. Still in the component, I have the hidden field:
<input type="hidden" name="[people_id][]" id="people_id" value={this.state.people} />
_form.html.erb:
<%= form_for resource, as: resource_name, url: registration_path(resource_name), :html => { :data => {:abide => ''}, :multipart => true } do |f| %>
<!-- react component goes here -->
<%= f.submit "Go", class: "large button" %>
<% end %>
The story is, guest can select few people during registration in one go. Those people will be notified when registration is complete. Think of it as "I am inviting these people to bid on my tender". Those numbers, in the array, are user_ids.
users/registrations_controller.rb
class Users::RegistrationsController < Devise::RegistrationsController
# POST /resource
def create
super do |resource|
ids = params[:people_id].pop # logs now as "people_id"=>["1,2"]
resource.save!(ids.split(",").map |b| Foo.create!(people_id: b.to_i) end)
end
end
end
New error on line resource.save:
no implicit conversion of Symbol into Integer
Edit #2
If I only have, in the create method:
ids.split(",").map do |b|
resource.save!(Foo.create!(people_id: b.to_i))
end
It works! Foo is created two times each with the correct people_id.
Because I am creating more objects: Bar, I do not know how to do that in:
resource.save!(<the loop for Foo> && Bar.create!())
The flow must be:
Device creates the User
Foo is created with the loop
Bar is created
etc
It has to be done that way as an User object is created on the fly.
In Rails you use parameter keys with brackets on the end to pass arrays.
However you should not concatenate the values as a comma seperated list but rather send each value as a seperate param:
GET /foo?people_ids[]=1&people_ids[]=2&people_ids[]=3
That way Rails will unpack the parameters into an array:
Parameters: {"people_ids"=>["1", "2", "3"]}
The same principle applies to POST except that the params are sent as formdata.
If you want a good example of how this works then look at the rails collection_check_boxes helper and the inputs it generates.
<input id="post_author_ids_1" name="post[author_ids][]" type="checkbox" value="1" checked="checked" />
<label for="post_author_ids_1">D. Heinemeier Hansson</label>
<input id="post_author_ids_2" name="post[author_ids][]" type="checkbox" value="2" />
<label for="post_author_ids_2">D. Thomas</label>
<input id="post_author_ids_3" name="post[author_ids][]" type="checkbox" value="3" />
<label for="post_author_ids_3">M. Clark</label>
<input name="post[author_ids][]" type="hidden" value="" />
Updated:
If you intend to implement you own array parameters by splitting a string you should not end the input with brackets:
<input type="hidden" name="[people_id][]" value="1,2,3">
{"people_id"=>["1,2,3"]}
Notice how people_id is treated as an array and the input value is the first element.
While you could do params[:people_id].first.split(",") it makes more sense to use the correct key from the get go:
<input type="hidden" name="people_id" value="1,2,3">
Also you don't really want to wrap the "root" key in brackets. Thats used in rails to nest a param key in a hash eg. user[name].

Pass Variables between Static Forms using Ruby on Rails

I am quite new to Ruby, but have some experience with programming. I am trying to figure out how to pass a variable collected in a form (SEARCH) using POST, to its controller (API) and then output it into another view (RESULT) that is also in the same controller.
I know the variable makes it to the API controller, because it shows up in the server log. But I can't figure out why it won't pass from there as an instance variable to the Result.html.erb page.
Routes.rb
Remixr::Application.routes.draw do
get "api/search"
post "api/result"
end
search.html.erb
<form action = "result" method="post">
Zip Code: <input type = "text" size = "5" name = "zip_code" />
Search Range: <input type = "text" size = "3" name = "range" />
<input type = "submit" value="Search" />
<input type = "reset" value="Reset Form" />
</form>
result.html.erb
Zipcode = <%= #zip_code %>
Radius = <%= #range %>
api_controller.rb
def search
end
def result
#zip_code = zip_code
#range = range
end
end
I know this some rudimentary stuff here, but I can't find anyone that shows a form used in one view , POST the form contents to its own controller to use another method in that controller and then output variable made in that method to another view under the same controller. I cut out a lot of the other processing that is going on until I am sure that I can pass variables in the fashion I laid out.
In the controller, use:
def result
#zip_code = params[:zip_code]
#range = params[:range]
end

Resources