expected, got String HABTM - string

This form:
<%= form_tag({:controller => "smart_lists", :action => "create"}, class: 'form-inline', :method => "POST") do %>
<%= label_tag :name %>
<%= text_field_tag :name %><br><br>
<% #people.each do |person| %>
<%= check_box_tag 'people_id[]', id: person.id %><%= label_tag person.name %><br>
<% end %>
<%= submit_tag "Create", class: 'btn' %>
Sends its check box list to a controller here:
def create
#smart_list = SmartList.new(params[:smart_list])
#smart_list.name = params[:name]
#smart_list.people = params[:people_id]
etc....
And I end up with this in my logs:
"name"=>"This is not working : (", "people_id"=>["{:id=>64}", "{:id=>8}", "{:id=>1}"]
And this in my view:
Person(#70133507313700) expected, got String(#70133469090180)
So, I guess my question is - Is there a way to break the that stuff out of those strings? Or can I send them through the form in a better way? Or catch them a better way in the controller?
Thanks for your help - Joey

I ended up changing the check_box_tag in the form to:
<td><%= check_box_tag 'people[]', person.id %></td>
Which gave me something like this in my params:
"people"=>["67", "11", "10", "23", "3", "1"],
And then in the controller I looped through the :people params and took out the ids:
if params[:people]
params[:people].each do |p|
#smart_list.people << Person.where(id: p)
end
end
I feel like this is pretty ugly - but it works. If anyone has a better way to form the view or controller I would still like to know a better way to do this. - Thanks

Related

Pagination of data in Middleman

I have a very long list of titles in my data file data/works.yml which looks more or less like this:
---
-
id: 947
title: "First"
-
id: 955
title: "Second"
The list is too long too display without pagination. How can I paginate index.html, where I want this list to be displayed?
It turned out to be much easier than I thought. It was only a matter of adding gem 'middleman-pagination' in Gemfile, in config.rb:
activate :pagination do
pageable_set :works do
data.works
end
end
and in index.html.erb
---
pagination:
for: works
per_page: 20
---
<ol>
<% pagination.each do |w| %>
<li>
<%= w.title %>
</li>
<% end %>
<%= link_to "Next page", pagination.next_page.url if pagination.next_page %>
As explained here: https://github.com/Aupajo/middleman-pagination

Searching Multiple Models with Ransack Rails 4

I'm trying to figure out how to search multiple models with Ransack. The goal is to have the search form in my shared header. I'm using a combination of their documentation, an old rails-cast, SO questions, and some code a friend shared with me. Right now I think it works, although I'm not sure because I can't get the results to show on my index page.
First, I created a search controller:
class SearchController < ApplicationController
def index
q = params[:q]
#items = Item.search(name_cont: q).result
#booths = Booth.search(name_cont: q).result
#users = User.search(name_cont: q).result
end
end
Next, I put this code in the header partial (views/layouts/_header.html.erb):
<%= form_tag search_path, method: :get do %>
<%= text_field_tag :q, nil %>
<% end %>
I added a route:
get "search" => "search#index"
My index.html.erb for the Search controller is empty and I suspect that is the problem, but I'm not sure what to place there. When I try something like:
<%= #items %>
<%= #users %>
<%= #booths %>
This is the output I get when I execute a search:
#<Item::ActiveRecord_Relation:0x007fee61a1ba10> #<User::ActiveRecord_Relation:0x007fee61a32d28> #<Booth::ActiveRecord_Relation:0x007fee61a20790>
Can someone please guide me on what the solution might be? I'm not sure if it's an index view problem, routing problem, or something else. On all of the tutorials the search field and results are only for one model so I'm a little confused on how to pull this off across multiple models.
Thanks!
The output you are getting is correct. Each of those variables contains an ActiveRecord_Relation object which can be treated like an array. Normally you'd do something like:
<% #items.each do |item| %>
<%= item.name %> # or whatever
<% end %>
<% #users.each do |user| %>
# and so on
Alternatively, you could combine your results #results = #items + #booths + #users and then:
<% #results.each do |result| %>
# display the result
<% end %>

How to get all locals in Express view

I am trying to figure out a way to get access to all the app.locals in the views. In my app.js I have
app.locals.title = "Title"
app.locals.page = "Page 1"
This is good, and in the views, I can access each with
<%= title %>
<%= page %>
However, is there a way (without doing something like app.locals.xyz.title) to get all the locals in the view so I can do something like this:
<% for(var i=0; i < locals.length; i ++ ){ %>
<li><%= locals[i] %></li>
<% } %>
You have to explitly pass it:
res.locals.locals = res.locals;
Then in the view:
<%= locals %>

Does EJS handle array.map(callback)?

I am passing an array of objects to an EJS template, which I would like to map into links using the regular .map() method of arrays. But for reasons I can't figure out, the callback I'm passing to map() doesn't work within EJS the way I'd expect, and I'm getting empty results.
My data is an array of objects, each with a "section" and a "name" key. This array is passed as "entries" to the template:
siteHeaders = [ { section: "home", name: "Home"},
{ section: "about", name: "About Me"},
... plus few more ]
The template looks like this, and I have it in a local variable called (surprise) template:
<% entries = entries.map(function(elem) { -%>
<% return -%>
<a href="/<%= elem.section %>">
<%= elem.name %>
</a>
<% } ) -%>
<p><%- entries.join(" | ") %></p>
The result of this template, when I call require('ejs').render(template, {entries: siteHeaders}) is:
<p> | | | | </p>
What I don't get is why this doesn't work in an EJS template, when the corresponding map call works just fine in REPL:
> siteHeaders.map(function(e){ return '' + e.name + '' })
[ 'Home',
'About Me',
'Portfolio',
'Blog',
'Contact' ]
>
Any clues?
This code should work:
<% entries = entries.map(function(elem) {
return '' + elem.name + '';
}) -%>
<p><%- entries.join(" | ") %></p>
You can't use simple html inside of functions. It's possible only in loops and conditions.
It's not as clean as join(' | '), but if you don't want to concatenate, you can do this:
<% entries.forEach(function(entry, i, entries){ %>
<%= entry.name %>
<%= i == entries.length-1 ? ' | ' : '' %>
<% } %>
I didn't manage to use map in EJS, but I found a way that at least for me is easy too
<ul>
<% for (item of toDoList) { %>
<li> <%= item %> </li>
<% } %>
</ul>

How to print a variable directly using EJS template engine?

I'm using Node.js with Express web framework (and EJS template engine).
When I have to print a variable I do something like:
<% if (value) { %>
<%= value %>
<% } %>
Can I do the same thing without open others brackets ? Like:
<% if (value) { PRINT VALUE } %>
Is this possible? How to print the variable?
I'm amazed to find that apparrently you can't do it, like in PHP:
<?php if ($value) : ?>
<?php echo $value; ?>
<?php endif; ?>
However a slightly better solution may be to do
<%= (value) ? value : '' %>
I say this assuming that the condition may occasionally be more complex, i.e.
<%= (str.length > 100) ? truncate(str) : str; %>
Which is much nicer than
<% if (str.length > 100) { %>
<%= truncate(str) %>
<% } %>
even if it is a slightly contrived example.
I'd love to be shown a direct command to do it, as per your original question.
There is now an outputFunctionName parameter that you can use. According to the documentation:
outputFunctionName Set to a string (e.g., 'echo' or 'print') for a function to print output inside scriptlet tags.
<% console.log(posts) %>
NB: Make sure you define your variable in any other file you have eg app.js file...
let posts = [];
app.get("/", (req, res) => {
res.render("home", {
posts: posts
});
});

Resources