form_for save input values to session variables - ruby-on-rails

I am trying to create a compare functionality for an index of schools. Currently I am using the following code which takes any checked school and adds it to the school_ids[] in the params.
In my gemfile:
gem 'will_paginate'
In my school's index.html.erb:
<%= form_tag compare_path, :method => 'get' do %>
<%= submit_tag "Compare" %>
<ul>
<% #schools.each do |school| %>
<li>
<%= check_box_tag'school_ids[]', school.id %>
<%= link_to school.name, school %><br>
<%= school.city %>, <%= school.state %>
</li>
<% end %>
</ul>
<% end %>
In my school controller I have:
def compare
#schools = School.find(params[:school_ids])
end
This works great as long as all of the check schools are on the same page. But since I'm using will_paginate to paginate the list of schools, if I change pages, the check boxes do not persist. I'm assuming I need to save to sessions somehow.

Do you mean you want to be able to add a check mark to a school A on page 1 of the index, go to page 2 of the index and add another check mark for school B, then submit the compare form and see schools A and B? If that's the case, then you're correct, you need to get the check boxes into the session. Attach a js click event, like
$('.checkbox_class').click(function(){
$.post('update_session_method', { school_id: $(this).val(), checked: $(this).is(:checked)]);
});
then add a controller method
def update_session_method
session[:school_ids] ||= []
if params[:checked]
session[:school_ids] << params[:school_id]
else
session[:school_ids].delete(params[:school_id])
end
end
then your compare method
def compare
#schools = School.find(params[:school_ids].merge(session[:school_ids] || []))
end

Related

How to exclude current item from related item search

I have a post view where I want to display related posts but what I have now includes the current post as well.
How would I go about removing the current item from the search?
I don't know how to use where.not() or != in this situation or if they're even the best thing to use.
This is what I have in my post show view:
<% #related[#post.blog_category_id]&.each do |rel| %>
<a href="/posts/<%= rel.friendly_id %>" class="img-cont">
<%= image_tag("Index/#{rel.thumbnail_link}", :alt => "#{rel.title}", class: "soundtrack-img top-drop") %>
<div class="img-mdl wellington"><h3 class="img-txt basic"><%= rel.title %></h3></div>
</a>
<% end %>
And in my posts_controller show method:
#related = Post.friendly.all.group_by(&:blog_category_id)
#related already includes all posts, you need to remove the current post from the list or skip it in the iteration:
Exclude the current one before iterating
<% #related[#post.blog_category_id].reject { |post| post == #post }&.each do |rel| %>
or just skip the iteration if the current one is the post in question:
<% #related[#post.blog_category_id]&.each do |rel| %>
<% next if rel == #post %>
Try using .offset(1). Something like:
#related = Post.friendly.all.group_by(&:blog_category_id).offset(1)
or
#related = Post.friendly.all.group_by(&:blog_category_id).order("created_at desc").offset(1)

Update JSon parsed vote using Ruby on Rails, possible without JQuery?

I am trying to make the vote total editable from a JSon parsed API. I have the following in my rosters controller:
def index
#rosters = HTTParty.get('https:api', :headers =>{'Content_Type' => 'application/json'})
#allrosters = Roster.all
#allrostershash = {}
#allrosters.each do |roster|
image_url = roster['image_url']
#allrostershash[ image_url ] = roster
end
#rosters.each do |roster|
img_url = roster['image_url']
unless #allrostershash[img_url]
Roster.create(roster)
end
end
end
def count_vote
roster_id = params[:id]
roster = Roster.find_by(roster_id)
newvote = roster.vote + 1
if roster.update({vote: newvote})
redirect_to rosters_path
end
end
Roster is the name of my class above. In my rails views I have the following:
<% #rosters.each do |roster| %>
<div class='each'>
<%= image_tag(roster['image_url'], class: 'image') %>
<%= hidden_field_tag(roster['id']) %>
<p class='name'> <%= roster['name'] %> </p>
<p class='title'> <%= roster['title'] %> </p>
<p> <%= roster['bio'] %> </p>
<p> <b> Want to work with <%= roster['name'] %>? </b> <%= link_to image_tag('yes.jpg', class: 'yes'), rosters_path, method: :patch %>
<br>
<%= roster['vote'] %> People have said Yes! </p>
<br>
</div>
<% end %>
I would like that every time someone clicks on yes.jpg, the roster['vote'] increases by 1.
Currently my routes are set up as follows:
get 'rosters', to: 'rosters#index'
patch 'rosters', to: 'rosters#count_vote'
I'm trying to accomplish this without jquery or ajax, that's why I have the if roster.update portion to redirect to rosters_path, so it basically refreshes the page upon click. Right now it isn't updating the vote total however, I'm not sure what I'm missing. I would like to do it all on a single page so if its not possible without JQuery, any guidance in right direction is appreciated.
count_vote will silently fail if it cannot find your Roster or if the update cannot be saved. Change it so it raises an exception of anything fails.
def count_vote
roster = Roster.find(params[:id])
roster.vote += 1
roser.save!
redirect_to rosters_path
end
find will raise RecordNotFound if the Roster cannot be found. save! will raise an error if the changes cannot be saved.
These are the only params currently for some reason ActionController::Parameters {"_method"=>"patch", "authenticity_token"=>"qbORnCLNnI9P1zUZ02VEP3qJMwYOGa5sGw6KblPFj99mvjwZQj9VnDQ2e+6ZStJi3PJZ3MidSMsdoWlwOgBN9w==", "controller"=>"rosters", "action"=>"count_vote"} permitted: false> how would I add an id param? – Sohel 5 hours ago
I'm not very familiar with how views work, but I think as in this example, I believe you need to pass the roster into rosters_path.
<%= link_to image_tag('yes.jpg', class: 'yes'), rosters_path(roster), method: :patch %>
Similarly, if you want count_vote to redirect back to the roster you just changed...
redirect_to rosters_path(roster)

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

Rails AJAX Search form reloading page

New to AJAX and search. I feel like I'm an inch away on this one, but I'm not sure what to fix. Also, my controller looks really hacky to me right now.
At any rate, I'm trying to create a search that allows users to search through blog posts on my page using AJAX. Here are the (relevant parts of the) parts:
posts_controller.rb
def show
#posts = Post.all.reverse
#post = Post.find(params[:id])
#link_num = 10
respond_to do |format|
format.html # show.html.erb
format.json { redirect_to #post }
end
end
def search
#link_num = 10
#posts = Post.all.reverse
#post = Post.find(params[:id])
#The including function returns the search results
#search = Post.first.including(params[:term])
render 'show'
end
What strikes me as "hacky" here is that I repeat all the variable assignments (there are others I didn't show cause they're not relevant). Shouldn't an AJAX call ideally not have to redefine/reload all these variables? Also, I have to pass :id to my search action through a hidden field. This feels weird/wrong to me.
show.html.erb
<h1 class="squeeze">Recent Posts</h1>
<%= form_tag("/search", method: "get", class: "search") do %>
<%= text_field_tag(:term, '', placeholder: "Search posts:") %>
<%= hidden_field_tag(:id, #post.id) %>
<%= submit_tag("Search", class: "btn search_button", remote: true) %>
<% end %>
<% if !#search%>
<ul>
<% #posts.first(#link_num).each do |p| %>
<li>(<%= p.created_at.strftime("%b %d, %Y") %>)</span></li>
<% end %>
<% if #posts.length > #link_num %>
<div class="link_disclaimer">
<h4>---</h4>
<h5><%= "Only showing #{#link_num} most recent posts." %></h5>
<h5>Search to narrow results.</h5>
</div>
<% end %>
</ul>
<% elsif #search.empty? %>
<h3>Term not found!</h3>
<% else %>
<ul>
<% #search.first(#link_num).each do |p| %>
<li>(<%= p.created_at.strftime("%b %d, %Y") %>)</span></li>
<% end %>
<% if #search.length > #link_num %>
<div class="link_disclaimer">
<h4>---</h4>
<h5><%= "Only showing first #{#link_num} relevant hits." %></h5>
<h5>Narrow search for more specific results.</h5>
</div>
<% end %>
</ul>
<% end %>
routes.rb
match '/search', to: 'posts#search'
Currently, the search itself works fine, with three major problems:
The aforementioned messiness of my Controller.
The fact that the whole page reloads. Isn't that the opposite of what AJAX is supposed to do? How can I get it to reload just the list of links?
The URL. It's super messy (i.e "/search?utf8=✓&term=limits&id=11&commit=Search"). I'd ideally have it remain untouched by the search, but if that's not possible, maybe just something like "/search?=". How's that done?
Based on the comment here is basic logic to make the function work(Sorry for no real code as that is too time consuming)
In controller you make a method say "search". The method need an argument which is the phrase to search. It gets the result from db and respond to JSON only with the result.
In template you have a search form.
In JS, you listen the event of user clicking the submit button, catch the characters they write, and handle it to ajax function.
Write Ajax code, preferred using jQuery's ajax(). Basically use ajax() to send the typed characters to controller method in #1 as argument. Then ajax() will get the response(the search result) from server.
Update the result in DOM. You can either add a new div to show search result, or replace current main content div to show result.

How can I display a list of three different Models sortable by the same :attribute in rails?

I have a Campaign model which has_many Calls, Emails, and Letters.
For now, these are each a separate Model with different controllers and actions (although I would like to start to think of ways to collapse them once the models and actions stabilize).
They do share two attributes at least: :days and :title
I would like a way to represent all the Calls, Emails, and Letters that belong_to a specific Campaign as a sortable collection (sortable by :days), in a way that outputs the model name and the path_to() for each.
For example (I know the below is not correct, but it represents the kind of output/format I've been trying to do:
#campaign_events.each do |campaign_event|
<%= campaign_event.model_name %>
<%= link_to campaign_event.title, #{model_name}_path(campaign_event) %>
end
Thanks so much. BTW, if this matters, I would then want to make the :days attribute editable_in_place.
Here is what I've got working, but want some additional insights
module CampaignsHelper
def campaign_events
return (#campaign.calls + #campaign.emails + #campaign.letters).sort{|a,b| a.days <=> b.days}
end
end
In the VIEW:
<% #campaign_events = campaign_events %>
<% #campaign_events.each do |campaign_event| %>
<% model_name = campaign_event.class.name.tableize.singularize %>
<p>
<%= link_to campaign_event.title, send("#{model_name}_path", campaign_event) %>
<%= campaign_event.days %>
</p>
<% end %>
Like this?
# controller
#campaign = Campaign.find(params[:id])
#campaign_events = (#campaign.calls + #campaign.emails + #campaign.letters).sort{|a,b| a.days <=> b.days}
# view
#campaign_events.each do |campaign_event|
<%= campaign_event.model_name %>
<%= link_to campaign_event.title, #{model_name}_path(campaign_event) %>
end
In controller you find all campaign events and sort it by days field

Resources