object in rails erb file not rendering properly - ruby-on-rails

I have an object like so
[
{"name": "ryan",
"age": "12",
},
]
And code in my erb file like so:
<div>
<% #list.each do |student| %>
<%= student.each do |k,v|%>
<%=v%>
<% end %>
<% end %>
</div>
I would assume that only the value of the hash in the list would be what gets rendered, so just ryan and 12 being rendered in the template. However in the template,
the values in the hash plus the whole list end up getting rendered, so something like
ryan, 12 {"name": "ryan", "age": "12", },
end up getting rendered. Im not sure why cause in the double for loop, I only have the v variable that I want rendered, not sure where the rest of the object is coming from. Am I missing something about how erb files work?

Would suggest you to use student.each_value as you are not using the keys.

Because you have <%= student.each (instead of just <% student.each) and so the value of the each is also being rendered (which is the full list you pass in).

Related

Rails 7 and Tailwind dynamic classes

I have a Rails 7 app with tailwind where I'm doing something like this:
#list = [{name: "Some", width: "3/12"}, {name: "other", width: "6/12"}]
# In the view
<%= render 'mypartial': list: #list %>
# In the partial
<% list.each do |item|%>
<div class="w-<%= item[:width] %>">
<%= item[:name] %>
</div>
<% end %>
The view generates the proper HTML (ex: <div class="w-6/12">), but the classes are not recognized in the browser. If I hard code them without passing the variable, everything works fine. Am I doing something wrong or missing something?
In case someone has the same issue, this is from the doc.
## Class names must be spelled out
For Tailwind to work, your class names need to be spelled out. They can't be programmatically composed. So no "text-gray-#{grade}", only "text-gray-500".
Atm, I added a list of dynamic variables in tailwind.config.js and it works ok, but you need to make sure all the dynamic variables are there.
purge: {
safelist: [
w-1/12,
....
],
},
Having dynamically created classes wont' work. An example:
# application_helper.rb
def badge(text, color)
tag.div text, class: "… bg-#{color}-500 …"
end
# show.html.erb
<%= badge('Completed', 'green') %>
This won't generate the bg-green-500 class in the build because the build process only scans the html.erb files as is, not when they are processed. So it never sees the bg-green-500 class.
You can also add the dynamic classes as a comment in your templates, if you know what options you need. I am trying this approach, since that way my dynamic styles are right next to where I use them.
Here Slim code:
/ To force tailwind to recognize the dynamic styles to apply
/ .hidden.pl-2.pl-4.pl-6
Despite the comment, meaning no render to HTML, Tailwind still picks it up nicely.
If you can figure an exhaustive list of the dynamic classes you're generating, then you could whitelist them in your tailwind.config.js file. To illustrate, let's say you have an erb file containing:
link_to 'Show', project_path, class: "text-#{color}-700"
You'd just need to list your dynamically generated values, such as:
module.exports = {
purge: {
safelist: [
'text-green-700',
'text-red-700',
],
},
}

How to give a form parameter a name in rails form?

I have a form with several radio buttons. The parameter it submits is an array of hashes. In the server logs, the array of hashes doesn't seem to have a name (probably because I need to give it one). Consequently, I can't tell params.require(:availability).permit(:<HERE>) to permit it, since I don't know what name to put inside .permit().
I've tried tinkering with the private controller method do relax requirements there, but I figure that's a hack rather than a good solution.
Here is my code in the view that generates the array of hashes
<%= form_tag("/availabilities/") do |f| %>
<%= label_tag :availability %>
<% #hours.each do |hour| %>
<%= hour[:time_slot] %>
<%= radio_button_tag hour.to_s, available_in_words(hour[:time_slot_available?]) %>
<%= radio_button_tag hour.to_s, available_in_words(!hour[:time_slot_available?]) %></br>
<% end %> <!-- ends hour loop -->
<div><%= submit_tag 'Save' %></div>
<% end %> <!-- ends form -->
Note: what is being submitted via this form doesn't match the fields in the Availability model - it's more raw and will need work after submission before creating/updating records in Availability. I'm not sure if that affects things
What I know so far
I thought label_tag would give the form parameter a name by which it could be referenced in params.require(:availability) but that leads to error param is missing or the value is empty: availability
Note
This is what params looks like after submission:
<ActionController::Parameters {"authenticity_token"=>"KEuNcLzuAcQj6b+0oQ0FzjOE35f1Xq3MNNomzTnC9SCML9kaWVIFgphCgDRy5cHowxQ/N4kodNIXYCAwtCPGnA==", "{:time_slot=>2020-08-22 18:00:00 +1000, :time_slot_available?=>false}"=>"Unavailable", "{:time_slot=>2020-08-22 20:00:00 +1000, :time_slot_available?=>false}"=>"Available", "commit"=>"Save", "controller"=>"availabilities", "action"=>"create"} permitted: false>
Accessing "authenticity_token" is easy enough: params[:authenticity_token]. But I can't meaningfully access the input from the radio buttons
The name is the first parameter to almost all the FormTagHelper methods.
radio_button_tag(name, value, checked = false, options = {})
https://api.rubyonrails.org/v5.1.7/classes/ActionView/Helpers/FormTagHelper.html#method-i-radio_button_tag
In Rack (which Rails sits on top of) you can pass hashes through the parameters by using brackets:
foo[bar][a]=1&foo[bar][b]=2
Will result in:
{
foo: {
bar: {
a: 1,
b: 2
}
}
}
You can whitelist nested hashes by passing a hash to .permit:
params.require(:foo).permit(bar: [:a, :b])
You can pass arrays through the parameters by using empty brackets:
foo[bar][]=1&foo[bar][]=2
Which will result in:
{
foo: {
bar: [1,2]
}
}
You can then whitelist an array by:
params.require(:foo).permit(bar: [])
[] will allow an array of permitted scalar values.
I'm not sure exactly what #hour.to_s returns but you might need to ensure that it is something actually suited to be used as a key in a formdata key/value pair and does not mess with Rack's parameter parser.

Rails output polymorphic associations

I want to implement a search functionality in my Rails app by using the pg_search gem. I've set up everything like it says in the documentation. Then I've set up a search controller with a show action:
def show
#pg_search_documents = PgSearch.multisearch(search_params)
end
The search itself works but I have a really annoying problem in my view. Whatever I do, it always outputs an array of PgSearch::Document objects. Even when I only write this in my view:
<%= #pg_search_documents.each do |document| %>
<% end %>
I get this (I've shortened it):
[#<PgSearch::Document id: 2, content: "…", searchable_id: 28, searchable_type: "Vessel">, #<PgSearch::Document id: 3, content: "…", searchable_id: 27, searchable_type: "Vessel">]
I know that pg_search sets up a polymorphic association which I've never dealt with before — could that be the problem?
Thanks in advance
<%= #pg_search_documents.each do |document| %>
<% end %>
This is a classic error, one I remember being puzzled over when I first started learning Rails. The mistake is using <%= %> with each. The return value of each is the array that you're iterating over (in this case, #pg_search_documents), and by using <%=, you're telling Rails to create a string from that array and insert it into your view. That generally isn't what you want: you want the view to be generated by the code inside the block you're passing to each.
Use <% #pg_search_documents.each do |document| %> instead (omitting the =) and you'll avoid the dump of the array's content.
You may also need to use .searchable as #blelump suggests, but I wanted to answer the other half of your question, as it's a common pitfall.
To get back to the original source model, searchable call is needed on these search result records, e.g:
<% #pg_search_documents.each do |document| %>
<%= document.searchable %>
<% end %>
You can also switch back to the source model within your controller, e.g:
#pg_search_documents = PgSearch.multisearch(search_params).collect(&:searchable)
Then, the #pg_search_documents will contain Vessel elements.

group_by education - rails 3

I am building a prototype of a education application using Rails 3, omniauth and the facebook graph api. So when a User log in to my application he uses his facebook account, I grab all his education history and his friends education_history.
I would like to group every User friends education likes this:
I have tried something like this:
<ul class="friends-list">
<%= current_user.friends.group_by(&:highschool_name) do |highschool_name|
p "<li>#{highschool_name}</li>"
end
%>
</ul>
And I get a syntax error.
The User tabel look like this:
[id, name, image, location, highschool_name, highschool_year, college_name, college_year, graduteschool_name, graduate_year ]
And the Friend tabel looks like this:
[id, uid, name, image, higschool_name, college_name, graduateschool_name, user_id]
How do solve my problem using active record, without loops because their are not effectivity.. right?
You can't use p or puts in ERB files. Think of ERB files as one big string concatenated together. Like "string 1" + "string 2" + "string 3".
That's all ERB does - it just pastes strings together into one big string. You can't call puts inside this concatenation operation. So everything in the ERB file needs to be a string. The output from a puts call just 'goes up in smoke' since a puts call does not return a string, it writes to stdout instead.
Next we look at group_by: it returns a Hash:
---------------------------------------------------- Enumerable#group_by
enum.group_by {| obj | block } => a_hash
------------------------------------------------------------------------
Returns a hash, which keys are evaluated result from the block,
and values are arrays of elements in enum corresponding to the key.
(1..6).group_by {|i| i%3} #=> {0=>[3, 6], 1=>[1, 4], 2=>[2, 5]}
So putting everything together we could do something like this:
<% current_user.friends.group_by(&:highschool_name).each do |hsname, friends| %>
<% next if hsname.blank? %>
<li><%= hsname %></li>
<% friends.each do |friend| %>
<%= image_tag(friend.img_url) %> # <- Or wherever you get the img url from
<% end %>
<% end %>

Adding Rails data to Highcharts series

I am trying to make a chart to display a users weight, using highcharts. I have all of the correct js files included and when passed a simple array of integers, it works just fine.
However I am unsure, having read the highcharts docs, how to pass the correct data into the series options using rails.
my user model is as follows:
A user has many weigh_ins, which has weight:float user_id:integer id:integer created_at:datetime fields. (if this is relevant)
Below is my view, as you can see i have tried to iterate through the users weights and then pass that as the data. I know it needs to be fed json and an array, but im not sure how to format my data to fit in that way.
borderWidth: 0
},
series: [{
pointInterval: <%= 1.day * 1000 %>,
name: 'weight',
data: <% #user.weigh_ins.each do |weight| %>
<%= weight.weight.to_json %>
<% end %>
}]
If there is any more code that needs posting, just shout.
any suggestions would be greatly appreciated.
Thata defo on the right track, however, the data is dynamic so a user can update their weights everyday, so the chart needs to update aswell. If i use the square brackets like above then the graph doesnt even render. Now i have this but it doesnt produce the correct output either. I need to find the weigh_ins for the correct user, then iterate through all of them and select the weight figure which is a float. Not sure how to tackle it.
data: <% user = #user.weigh_ins %>
<% user.each do |user_weight| %>
[<%= user_weight.weight %> ]
<% end %>
I'm something similar with this code:
<% bio_array = Array.new(#bio.size) %>
<% #biometrics.each_with_index {|x, index| %>
<% bio_array += [x[:weight]] %>
<% } %>
(... some code ...)
series: [{
name: 'Some Name',
data: <%= bio_array %>
Please note that this code is not optimized for you case (in my case i have other logic that i omitted for being useless to your case - i had a multidimensional arrays with [data and value]).
if you want to parse data like that , you don't really have to use Json , becoz since yo don't update dynamically , you can just echo it like [34,32,24,25,12] bt first you hv to make that String from Ruby , and that's exactly what is json is used for too , check your Json output,
btw try echo some Ruby String like
=> 1,2,3,4,5 [<% echo str %> ]
and if your json out put hv no squre brackets [] then try adding them
data:[ <% #user.weigh_ins.each do |weight| %> ]

Resources