Rails 5 - Iterating over part of an array for the view - ruby-on-rails

I currently use EasyAutoComplete for a search form. If you hit 'View All' it redirects to the same page but with params[:name] to show all cards.
I render this with:
<% #cards.in_groups_of(6, false).each do |group| %>
<div class='row'>
<% group.each do |card| %>
<div class='col-sm-2 col-md-2'>
<div class="wrapperImg">
<%= link_to image_tag(card.image_url, class: "img-responsive"), {:controller => "cards", :action => "show", :id => card.id }%>
</div>
</div>
<% end %>
</div>
</div>
<% end %>
However, if you look up a specific set of cards it's going to return a couple hundred (or more) of essentially the same card. I can identify these cards by a parameter(rarity)
I was originally going to try to modify it in the controller, but that is an issue because the 'def index' makes the EasyAutoComplete work
def index
wild_search = "%#{params[:name]}%"
#cards = Card.order(multiverse_id: :desc).limit(30)
# debugger
##cards = #cards.where("name like :name", name: wild_search).page(params[:page]) if params[:name]
#cards = #cards.where("name like :name OR setName like :name", name: wild_search).page(params[:page]) if params[:name]
end
Is there a way for me to do something like
cards = #cards.where('rarity IS NOT ?', 'Land') or something similar in the view, then modify my output from #cards.in_group_of to cards.in_group_of? Or is there a way to use the Controller to do this and use def search instead of def index?
Welcome any input.

Like this?
<% #cards.where.not(rarity: "Land").in_groups_of(6, false).each do |group| %>
http://api.rubyonrails.org/classes/ActiveRecord/QueryMethods/WhereChain.html

Related

How can I dynamically update search results based on form input in Rails?

I want site visitors to be able to view nearby shows within a radius that can be input via dropdown form. I have a view that displays nearby shows using the Geocoder gem:
<h3> Shows near <%= request.location.city %> </h3>
<%= form_for #nearby_shows.first do |f| %>
<p> Radius (in miles): <%= f.select(:radii, [10,20,30,40,50], {},
:style => "width:50px", :selected => f.object.radii, :onchange =>
"location.href = '#{shows_path}'") %> </p>
<% end %>
<ul class="users">
<% #nearby_shows.each do |nearby_show| %>
<li>
<%= link_to nearby_show.show_name, nearby_show %>
</li>
<% end %>
</ul>
Right now the selection doesn't affect anything, and the selection isn't remembered in the form when the page refreshes.
The model, show.rb contains:
attr_accessor :radii
And the shows controller contains:
def index
#shows = Show.all
#radii = 50
#nearby_venues = Venue.near("Boulder, CO",#radii,:select =>
"id").to_a
#nearby_shows = Show.where(show_venue: #nearby_venues)
end
In production, I'll be using request.location.city, but in development I'm just using "Boulder, CO" as an example.
How can I set #radii using the input select form? I am concerned that form_for will not permit me to change a variable for the list of entities #nearby_shows.
If you want a fast AJAX solution, here's what I would do
First, add an ID to your list so it's easy to manipulate
<ul id="my_id" class="users"></ul>
I really don't understand why you need that <%= form_for #nearby_shows.first %> for ? If I understand well, you just want to show a select, and update the list of nearby shows based on what the user selects ?
routes.rb
resource :shows do
get 'update_nearby', on: :collection, constraints: { format: 'js' }
end
# GET /shows/update_nearby, meant to be used only with AJAX
your_view.html.erb
<%= form_tag update_nearby_shows_path, remote: :true do |f| %>
<p> Radius (in miles): <%= select_tag(:radii, [10,20,30,40,50], {},
:style => "width:50px", :selected => #radii, :onchange =>
"location.href = '#{shows_path}'") %> </p>
<% end %>
<!-- On Submit, it will request a JS response
You can add some JS to submit the form everytime the select changes -->
Add some JS specific respone
your_controller.rb
def update_nearby
find_nearby_shows
end
private
def find_nearby_shows
#radii = params[:radii] ? params[:radii] : 50
#nearby_venues = Venue.near("Boulder, CO",#radii,:select =>
"id").to_a
#nearby_shows = Show.where(show_venue: #nearby_venues)
end
update_nearby.js.erb
<% if #nearby_shows %>
// Empty the list
var id = $("#my_id").empty()
<% #nearby_shows.each do %>
// Add one <li> per show
$("<li>", { 'html': "<%= escape_javascript(link_to(nearby_show.show_name, nearby_show)) %>"}).appendTo(id)
<% end %>
<% end %>
Bonus : you said you wanted to save the radius ? You can actually try to add it to the user session
def index
...
#radii = session[:saved_radii] ? session[:saved_radii] : DEFAULT_RADIUS
...
end
def update_nearby
find_nearby_shows
session[:saved_radii] = #radii
end
But if you really want to save it for the user, you should have a preferred_radii field in your User model

Parameters not being read even though they appear to be passed

I'm making a form that creates more than one record for the user depending on how many items the user decides to check off in the form using checkboxes.
Currently, I'm running into an error where param is missing or the value is empty: itemrecord even though in the log, it appears that params are passing through:
{"utf8"=>"✓", "authenticity_token"=>"m2NMruoFRr6lpsuVMK9UthlY0bsJsPmf1LWce2uKaH4=", ":item_name"=>["Backpack", "Water filter"], "commit"=>"Go!"}
Model relationship is that a User has_many :inventories
Controller code:
def create
#itemrecord = #current_user.inventories.build
items_to_be_saved = []
inventory_params.each do |i|
items_to_be_saved << ({ :signup_id => #current_user.id, :item_name => i })
end
if Inventory.create items_to_be_saved
flash[:success] = "Thanks!"
redirect_to root_path
else
render new_inventory_path
end
end
def inventory_params
params.require(:itemrecord).permit(:item_name)
end
View code:
<%= form_for #itemrecord do |f| %>
<!-- In case you're wondering, the #wishlist below is basically a hash of categories of items and items. This hash is updated in the controller, and then used by multiple views to create the same table of items. -->
<% #wishlist.each do |category, list| %>
<div class="col-xs-2">
<div class="form-group box">
<h5> <%="#{category}"%> </h5>
<% list.each do |thing| %>
<%= check_box_tag ":item_name[]", "#{thing}" %>
</br>
<% end %>
</div>
</div>
<% end %>
<%= f.submit "Go!", class: "btn btn-primary btn-large btn-block" %>
</div>
<% end %>
By the way I also tried changing :item_name to :item_names to account for the array based on what else I read on SO, but that didn't fix it either
Take a look at your inventory_params function. You're saying that you require an itemrecord, and permit an item_name attribute. Observe:
def inventory_params
params.require(:itemrecord).permit(:item_name)
end
However, in the parameters being passed, there is no reference to an itemrecord object whatsoever, but there is a reference to item_name. A quick change to your inventory_params method, removing the :itemrecord requirement and instead requiring :item_name, will fix your issue.
def inventory_params
params.require(:item_name)
end
While this isn't necessarily the best way to go about doing this (I'd suggest reading up on your Active Record Form Helpers), it should solve your issue.

How to call a method from Application Controller in any given controller test

I have a controller that POSTs a new instance of a model into a database after the user fills out a form. This form is created using an each do that loops over a series of inventory items defined in the Application Controller.
In other words, this is the view code:
<%= form_for #requestrecord, :html=> {:id => 'form'} do |f| %>
<div class="col-xs-12">
<p><b>Items we have available</b></p>
</div>
<% #inventory.each do |category, list| %>
<div class="col-xs-2">
<div class="form-group box">
<h5> <%="#{category}"%> </h5>
<% list.each do |thing| %>
<%= f.check_box(:items, {:multiple => true}, "#{thing}") %>
<%= f.label(:items, "#{thing}") %>
</br>
<% end %>
</div>
</div>
<% end %>
There is a method in the application controller that defines inventory:
def inventory
#inventory = { some hash }
end
And then this method is called in the Requests controller that I'm trying to test:
def create
inventory
#requestrecord = Request.new(request_params)
end
The problem is in my Rspec controller test, I now have to manually define this inventory again like so:
before do
#inventory = { some hash }
end
Instead of doing this, is there a way to call the method from the Application Controller in the before statement? The #inventory is a rather long hash...
Thanks!
You can access your controller in rspec with 'controller', so
before do
#inventory = controller.inventory
end
should do the job!

Pulling records from one table (products) depending on a value in another (department)

I have a Products table and a Departments table.
In products model:
has_one :department
In departments model:
belongs_to :products
I also have a view in my products controller that lists all departments as so:
<% #departments.each do |department| %>
<div class="column_entry">
<%= link_to image_tag(department.image_attachment), products_of_a_given_main_cat_url %>
</div>
<% end %>
Those load up fine. When I click on one of the images I want products_of_a_given_main_category view to dynamically populate with products from the department whose image I clicked.
In my products controller:
def products_of_a_given_main_cat
#products = Product.all
#department = Department.where(:name == :department)
respond_to do |format|
format.html # index.html.erb
format.json { render json: #products }
end
end
and in the view:
<div class="the_grid_prod">
<% #products.each do |product| %>
<% if product.department == #department.name %>
<div class="column_entry">
<%= link_to image_tag(product.product_image.url(:normal_page_size)), products_content_url(product.id) %>
</div>
<% end %>
<% end %>
</div>
When I click on the image for a department that I'm certain has products the page loads but there are no products. I'm certain I'm doing something very wrong but I'm not really sure what it is.
in routes file:
get 'products/products_of_a_given_main_cat' => :products_of_a_given_main_cat, :as => :products_of_a_given_main_cat
The problem is this:
#department = Department.where(:name == :department)
The :department is a symbol, not a string, and not a variable. Basically it is a number deep down, definietly not a name. Also, this will evaluate to Departments which have a name false. Don't do evaluation in the where part, only a hash.
You need the params[:department] if you get it from the request.
#department = Department.where(:name => params[:department])
Update:
Please modify your request link:
<%= link_to image_tag(department.image_attachment), products_of_a_given_main_cat_url(:department => department.name) %>
This will introduce a new parameter to the request, and it will work for you with the condition written above.
So to solve this problem I changed my associations as #TomL suggested in his comment. I also changed the following:
In products controller I deleted
#department = Department.where(:name => params[:department])
and changed
#products = Product.all
to
#products = Product.where(:department => params[:department])
The products_of_a_give_main_category_view now looks like this:
<div class="the_grid_prod">
<% #products.each do |product| %>
<div class="column_entry">
<%= link_to image_tag(product.product_image.url(:normal_page_size)), products_content_url(product.id) %>
</div>
<% end %>
</div>
Thanks to both #Matzi and #TomL for their help. It's greatly appreciated.

Cannot reverse order because of pagination

I want to order users by descending. However, when I add .reverse it reverses the users a page at a time, not all together.
show_followers:
<%= render #users.reverse %>
<%= will_paginate %>
Users/_user:
<%= link_to user.name, user %>
<% unless #user.nil? %>
<% if request.path == "/users/#{#user.id}/listening_to" %>
<br/>
<span id="member_since"><%= "Listening Since" %> <%= #user.relationships.find_by_followed_id(user.id).created_at.strftime("%b. %d, %Y") %></span>
<% end %>
<% if request.path == "/users/#{#user.id}/listeners" %>
<br/>
<span id="member_since"><%= "Listener Since" %> <%= user.relationships.find_by_followed_id(#user.id).created_at.strftime("%b. %d, %Y") %></span>
<% end %>
<% end %>
Controller:
#users = #user.followed_users.paginate(page: params[:page])
It seems Rails intelligently orders by the relationships_create like I wanted but it's in ascending order. I want the most recent follower to show up on the top of the list.
In the controller action, you probably have some code that looks something like this: #users = User.paginate(:page => params[:page]).
You need to put the reverse in that statement, so it looks like this: #users = User.paginate(:page => params[:page]).order('id DESC') (perhaps with id replaced by created_at).
#users = #user.followed_users.reverse.paginate(page: params[:page])
Reverse at the controller level prior to pagination

Resources