How to convert a string to an array using Ruby on Rails - ruby-on-rails

I have a text field that takes in a string value, like
"games,fun,sports"
My main goal here is to take the string and turn it into a Array like this:
[games, fun, sports]
in the filters attribute for the integrations object I have. Right now I have the beginning of a method that doesn't seem to work.
Here is my code:
View:
<%= form_for #integrations, url: url_for(:controller => :integrations, :action => :update, :id => #integrations.id) do |f| %>
<%= f.label :filters %>
<%= f.text_field :filters, class: "filter-autocomplete" %>
<%= f.submit "Save" %>
<% end %>
That is the text field that takes in the string.
Model:
def filters=(filters)
end
This is the place that I'd like to make the switch from string to array.
Controller:
def update
#integrations = current_account.integrations.find(params[:id])
if #integrations.update_attributes(update_params)
flash[:success] = "Filters added"
redirect_to account_integrations_path
else
render :filters
end
end
def filters
#integrations = current_account.integrations.find(params[:id])
end
private
def update_params
[:integration_webhook, :integration_pager_duty, :integration_slack].each do |model|
return params.require(model).permit(:filters) if params.has_key?(model)
end
end
So, recap: I have a integrations model that takes in a string of filters. I want a method that will break up the string into an element of filter attributes.
Here is the object that I'm trying to add the filters to:
Object:
id: "5729de33-befa-4f05-8033-b0acd5c4ee4b",
user_id: nil,
type: "Integration::Webhook",
settings: {"hook_url"=>"https://hooks.zapier.com/hooks/catch/1062282/4b0h0daa/"},
created_at: Mon, 29 Aug 2016 03:30:29 UTC +00:00,
owner_id: "59d4357f-3210-4ddc-9cb9-3c758fc1ef3a",
filters: "[\"Hey\", \"ohh\"]">
As you can see the filters is what I'm trying to modify. Instead of this in the object:
"[\"Hey\", \"ohh\"]"
I would like this:
[Hey, ohh]

It's not clear what you're after, but generally, when you have a string like:
"games,fun,sports"
you can use split(',') to break it on the commas and turn it into an array of strings:
"games,fun,sports".split(',') # => ["games", "fun", "sports"]
If you're receiving a JSON encoded array of strings, it'll look like:
'["games", "fun", "sports"]'
AKA:
'["games", "fun", "sports"]' # => "[\"games\", \"fun\", \"sports\"]"
which can be returned to a Ruby array of strings easily enough:
require 'json'
JSON['["games", "fun", "sports"]'] # => ["games", "fun", "sports"]

One option is to use JSON.
require 'json'
filters = "[\"Hey\", \"ohh\"]"
JSON.parse(filters)
returns:
["Hey","ohh"]

You need to remove extra characters and then split the string into array using the split pattern like this:
"[\"Hey\", \"ohh\"]".gsub(/(\[\"|\"\])/, '').split('", "')
Which returns:
["Hey", "ohh"]

Related

update_all ruby on rails

Im trying to update all post where a condition is true. If the condition is true should the field category_id be set to params[:category_id]
Every time im trying to do it will my code update all post where the condition is true and set it to "--- !ruby/hash:ActionController::Parameters categori_id: '169'"
Instead of just 169.
My controller action look like this
def update_all_notes
#deletefolder = Categori.find(params[:id])
System.where(:categori_id => params[:id]).update_all(:categori_id => params[:categori_id])
redirect_to :back
end
My form look like this:
<%= form_tag update_all_notes_path(category.id) do %>
<%= collection_select :kategori_id, :id, #current_company.category.where.not(:name => category.name), :id, :name %>
<button>move</button>
this is the parameters i send to the action
"categori_id"=>{"categori_id"=>"169"},
"id"=>"168"}
Thanks in advance
From your hash you should replace params[:categori_id] to be params[:categori_id][:categori_id]
as the hash is { "categori_id" => {"categori_id" => 169}, "id" => X }
Example of update_all use:
ids = [1,2,3]
records = Mammal::Human.where(id: ids)
records.update_all(status: :enlightenment, enlightenment_at: Time.zone.now, enlightenment_by: "myself")
I will rather use status: value over :status => value syntax

Rails 3 - Trying to parse JSON and return hash

I'm trying to create a simple two-page web-app that allows users to search for words, then display their definitions on a new page.
The problem is that when searching for a word, I'm not getting any response back from my model file.
I think the problem is trying to convert the JSON request to a hash, then accessing/displaying the hash in the view (not sure how to go about this).
app/views/index.html.erb
<%= form_tag("/search", method: "get") do %>
<%= text_field_tag :search, params[:search], :class => "search-form" %>
<%= submit_tag nil, :class => "search-glass", :src => "search-icon.png", :type => "image" %>
<% end %>
app/controllers/words_controller.rb
def search
#word = Word.search(params[:search])
render layout: "application", template: "words/index"
end
app/models/word.rb
class Word
require 'rubygems'
require 'json'
attr_accessor :search
def self.search(search)
# Get back JSON response
response = Wordnik.word.get_definitions(search)
# Parse JSON to an array of hashes?
hash_result = JSON.parse(response)
end
end
When searching for a single word, I'm getting the following error (screenshot):
Any help is greatly appreciated.
When you call Wordnik.word.get_definitions(search), an Array of Hashes is returned, not a JSON string. Remove the line:
hash_result = JSON.parse(response)
Also having your API key publicly available on Github is probably not a good idea.

How to display Rails select field values rather than stored integers in other views

I'm using a select field in a Rails app that is NOT tied to a related model, but stores integer values for a static series of options , i.e.,
<%= select (:this_model, :this_field, [['Option1',1],['Option2',2],['Option3',3],['Option4',4]] ) %>
In a show/ index view, if I want to display the option text (i.e. Option1, Option2, etc) rather than the integer value stored in the database, how do I achieve this?
Thanks for helping a noob learn the ropes!
EDIT
Based on Thorsten's suggestion below, I implemented the following. But it is returning nil, and I can't figure out why.
Invoice model:
##payment_status_data = { 1 => "Pending Invoice" , 2 => "Invoiced" , 3 => "Deposit Received", 4 => "Paid in Full"}
def text_for_payment_status
##payment_status_data[payment_status]
end
Invoice show view:
Payment Status: <%= #invoice.text_for_payment_status %>
In the console:
irb > i=Invoice.find(4)
=> [#<Invoice id: 4, payment_status: 1 >]
irb > i.text_for_payment_status
=> nil
I've tried defining the hash with and without quotes around the keys. What am I missing?
something like this would work:
<%= form_for #my_model_object do |form| %>
<%= form.label :column_name "Some Description" %>
<%= form.select :field_that_stores_id, options_for_select({"text1" => "key1", "text 2" => "key2"}) %>
<% end %>
Update
If you later want to display the text you can get it from a simple hash like this:
{"key1" => "text 1", "key2" => "text2"}[#my_object.field_that_stores_id]
But you better store this hash somewhere in a central place like the model.
class MyModel < ActiveRecord
##my_select_something_data = {"key1" => "text 1", "key2" => "text2"}
def text_for_something_selectable
##my_select_something_data[field_that_stores_id]
end
end
Then you can use it in your views like
#my_object.text_for_something_selectable
There are many possible variations of this. But this should work and you would have all information in a central place.
Update
Ok, I used something similar for our website. We need to store return_headers for rma. Those need to store a return reason as a code. Those codes are defined in an external MS SQL Server Database (with which the website exchanges lots of data, like orders, products, and much more). In the external db table are much more return reasons stored than I actually need, so I just took out a few of them. Still must make sure, the codes are correct.
So here goes he model:
class ReturnHeader < AciveRecord::Base
##return_reason_keys = {"010" => "Wrong Produc",
"DAM" => "Damaged",
"AMT" => "Wrong Amount"}
def self.return_reason_select
##return_reason_keys.invert
end
def return_reason
##return_reason_keys[nav_return_reason_code]
end
end
Model contains more code of course, but that's the part that matters. Relevant here is, that keys in the hash are strings, not symbols.
In the views i use it like this:
In the form for edit:
<%= form_for #return_header do |form| %>
<%= form.label :nav_return_reason_code "Return Reason" %>
<%= form.select :nav_return_reason_code, options_for_select(ReturnHeader.return_reason_select, #return_header.nav_return_reason_code) %>
<% end %>
(Maybe no the most elegant way to do it, but works. Don't know, why options_for_select expects a hash to be "text" => "key", but that's the reason, why above class level method returns the hash inverted.)
In my index action the return reason is listed in one of the columns. There I can get the value simply by
#return_headers.each do |rh|
rh.return_reason
end
If you have trouble to get it run, check that keys a correct type and value. Maybe add some debug info with logger.info in the methods to see what actual data is used there.

output formated json with rails 3

I use rails 3.0.3
A javascript auto complete needs data like this
{
query:'Li',
suggestions:['Liberia','Libyan Arab Jamahiriya','Liechtenstein','Lithuania'],
data:['LR','LY','LI','LT']
}
My action is
def autocomplete
#query = params[:query]
#customers = Customer.where('firstname like ?', "%#{#query}%")
render :partial => "customers/autocomplete.json"
end
My view is
{
query:'<%= #query %>',
suggestions: <%= raw #customers.map{|c| "#{c.firstname} #{c.lastname}" } %>,
data: <%= raw #customers.to_json %>
}
it returns
{
query:'e',
suggestions: ["customer 1", "customer 2"],
data: [1, 3]
}
it's not working because the data for suggestions/data should be between simple quote...
I cannot use the to_json method, because it'll returns all the content of my object.
Any suggestion?
cheers
Note: this is way out of date, Jbuilder is by far a better option.
There are two ways you can approach this. If you simply need a subset of the fields in an object, you can use :only or :except to exclude what you don't want.
#customer.to_json(:only => [:id, :name])
in your example it looks like you need to return json in a specific format, so simply serializing an array of results won't work. The easiest way to create a custom json response is with the Hash object:
render :json => {
:query => 'e',
:suggestions => #customers.collect(&:name),
:data => #customers.collect(&:id)
}
I've tried using partials to build json responses, but that doesn't work nearly as well as simply using Hash to do it.
Formatting the first and last names as a single string is something you are likely to do a lot in your views, I would recommend moving that to a function:
class Customer < ActiveRecord::Base
...
def name
"#{first_name} #{last_name}"
end
def name=(n)
first_name, last_name = n.split(' ', 2)
end
end
Just some convenience functions that makes your life a little easier, and your controllers/views cleaner.
If Adam's response won't work for you, this may do it (admittedly not the most elegant solution):
{
query:'<%= #query %>',
suggestions: [<%= raw #customers.map{|c| "'#{c.firstname} #{c.lastname}'" }.join(", ") %>],
data: [<%= raw #customers.map{|c| "'#{c.id}'" }.join(", ") %>]
}
I've seen something like this in a .erb:
<%= raw
{
:query => #query,
:suggestions => #customers.map{|c| "#{c.firstname} #{c.lastname}" },
:data => #customers
}.to_json
%>
If thinking of preparing data to be consumed by other programs as presentation logic, this might make sense to you.
FWIW I like it.

Passing hash as values in hidden_field_tag

I am trying to pass some filters in my params through a form like so:
hidden_field_tag "filters", params[:filters]
For some reason the params get changed in the next page. For example, if params[:filters] used to be...
"filters"=>{"name_like_any"=>["apple"]} [1]
...it gets changed to...
"filters"=>"{\"name_like_any\"=>[\"apple\"]}" [2]
note the extra quotations and backslashes in [2] when compared to [1].
Any ideas? I'm attempting to use this with searchlogic for some filtering, but I need it to persist when I change change objects in forms. I would prefer not to have to store it in session.
My solution was just to re-create each of param with key-value pair:
<% params[:filters].each do |key,value| %>
<%= hidden_field_tag "filters[#{key}]",value %>
<% end %>
You actually want/need to 'serialize' a hash using hidden fields.
Add this to your ApplicationHelper :
def flatten_hash(hash = params, ancestor_names = [])
flat_hash = {}
hash.each do |k, v|
names = Array.new(ancestor_names)
names << k
if v.is_a?(Hash)
flat_hash.merge!(flatten_hash(v, names))
else
key = flat_hash_key(names)
key += "[]" if v.is_a?(Array)
flat_hash[key] = v
end
end
flat_hash
end
def flat_hash_key(names)
names = Array.new(names)
name = names.shift.to_s.dup
names.each do |n|
name << "[#{n}]"
end
name
end
def hash_as_hidden_fields(hash = params)
hidden_fields = []
flatten_hash(hash).each do |name, value|
value = [value] if !value.is_a?(Array)
value.each do |v|
hidden_fields << hidden_field_tag(name, v.to_s, :id => nil)
end
end
hidden_fields.join("\n")
end
Then, in view:
<%= hash_as_hidden_fields(:filter => params[:filter]) %>
This should do the trick, even if you have a multilevel hash/array in your filters.
Solution taken http://marklunds.com/articles/one/314
I just wrote a gem to do this called HashToHiddenFields.
The core of the gem is this code:
def hash_to_hidden_fields(hash)
query_string = Rack::Utils.build_nested_query(hash)
pairs = query_string.split(Rack::Utils::DEFAULT_SEP)
tags = pairs.map do |pair|
key, value = pair.split('=', 2).map { |str| Rack::Utils.unescape(str) }
hidden_field_tag(key, value)
end
tags.join("\n").html_safe
end
Here's how I managed to pass a parameter value through my view - that is, from View A through View B and on to the controller:
In View A (index):
<%= link_to 'LinkName', {:action => "run_script", :id => object.id} %>
In View B (run_script):
<%= form_tag :action => 'index', :id => #object %>
<%= hidden_field_tag(:param_name, params[:id]) %>
In the controller:
Just reference params[:param_name] to make use of the value.
The key transition that wasn't documented anywhere I could find is where {... :id => object.id} from View A is passed on to View B as <%... :id => #object %>, which View B then passes on to the controller as (:param_name, params[:id]) through the hidden_field_tag construct.
I didn't see this documented anywhere but after perusing several posts across several sites including this post (whose syntax provided the key inspiration), the solution finally gelled. I've seen the caveats on hidden fields pertaining to security but have found no other way to do this given my current design, such as it is.
it's because when you convert in HTML with your hidden_field_tag, the backquote is add. After when you received it like a string not a Hash.
The Hash type can't exist in HTML. You have only string. So if you want pass your hash (not recommend by me), you need eval it when you received it. But can be a big security issue on your application.
As a caveat to Vlad's answer, I had to use raw:
<%= raw hash_as_hidden_fields(:filter => params[:filter]) %>
to get it to work in Rails 3.1.1. Essentially, the text being output was being escaped, eg., "<" becoming "&lt".
Assuming the hash is strings, symbols, numbers, and arrays, you can call eval to convert the params string of the hash from the hidden_fields form back into a hash in the controller. Then the backslash escape characters for the quotes added are no longer an issue:
hash = eval(params["hash_string"].to_s)
Credit to the following article for helping identify this simple solution for my case:
How do I convert a String object into a Hash object?
Keep in mind the contents of the params should be cleaned with .require and .permit.

Resources