Rails - refreshing page with new table entries - javascript

The goal I am trying to achieve is to let the user click on a button which will refresh to page filter that search. My page is dedicated to music artists and would like that once the user selects "Pop", that the page refreshes showing only "pop" artists.
Here is the html + ruby that I am using to display the artists:
<% #prints the artists that match the search, prints all for empty search %>
<% #artists.each_slice(3) do |artists| %>
<div class="row">
<% artists.each do |artist| %>
<div class = "artist_images">
<%= link_to image_tag(artist.artist_art, class: 'show_image'), artist_path(artist) %><br/><br/>
</div>
<% end %>
</div>
<% end %>
<% #prints message showing that the search does not match %>
<% if !#artists.present? %>
<h3><center style = "color: white">There are no artists containing the term(s) "<%= params[:search] %>". Please try 'Adele', 'Drake', 'Kanye West', or 'Taylor Swift'</center></h3>
<% end %>
The controller has the following methods:
def index
#artists = Artist.all
end
def randomPop
#artists = Artist.where(:genre => "\nPop").random(9)
end
Does anyone know how I can go about changing the variable #artists from All artists to those in pop only through a button click?

in your view,
<%= button_to "Pop", artists_path, method: :get, params: { artist_genre: "Pop" } %>
in your controller,
def index
if params[:artist_genre]
#artists = Artist.where(:genre => params[:artist_genre]).random(9)
else
#artists = Artist.all
end
end

This classic railscast episode is on point. I would use that for how you set up your search box. The only thing you might alter/update:
if search
find(:all, :conditions => ['name LIKE ?', "%#{search}%"])
else
find(:all)
end
Should probably be a where clause based on your situation"
if search
where("genre = ?", your_genre)
else
all
end

Related

How to make multiple loadmore buttons assigned to each individual list on one page

Hello I have 3 lists on one page that will display and each list has a load more button. I want to be able to click the loadmore button and load 3 items per click.
The problem that I am facing is that when i click the load more button, the second page doesnt show up but on the 2nd click it populates only the last page.
Another is when for instance the button is clicked on completed and then clicking the button on expired creates duplicates of the expired list.
So pretty much the all of the buttons are changing all of the lists eventhough they are not corresponding to them.
I realize that im using url_for which may be the reason im in this problem. perhaps there is a better way to achieve this?
When clicking load more button on the console i get:
www.mywebsite.com/your_essays?page_completed=2".
www.mywebsite.com/your_essays?page_completed=3".
www.mywebsite.com/your_essays?page_expired=2".
This shows what the current page is based on the url, however if i have multiple lists how can i achieve this to make each list separate from each other? is there a better way to do this??
reservations_controler.rb:
def your_essays
user = current_user
#reservations = user.reservations.where("user_id = ?", current_user.id).where("status = ?", true)
#pending
#reservations_pending = user.reservations.where("turned_in = ?", false).where("completed = ?", false).where("due_date >= ?", DateTime.now).order(created_at: :desc).page(params[:page_pending]).per_page(3)
#reservations_pending1 = user.reservations.where("turned_in = ?", false).where("completed = ?", false).where("due_date >= ?", DateTime.now).order(created_at: :desc)
#completed
#reservations_completed = user.reservations.where("turned_in = ?", true).where("completed_doc_updated_at <= due_date", true).order(created_at: :desc).page(params[:page_completed]).per_page(3)
#reservations_completed1 = user.reservations.where("turned_in = ?", true).where("completed_doc_updated_at <= due_date", true).order(created_at: :desc)
#expired
#reservations_expired = user.reservations.where("due_date <= ?", DateTime.now).where("turned_in = ?", false).where("completed = ?", false).order(created_at: :desc).page(params[:page_expired]).per_page(3)
#reservations_expired1 = user.reservations.where("due_date <= ?", DateTime.now).where("turned_in = ?", false).where("completed = ?", false).order(created_at: :desc)
end
my_essays.html.erb:
<div id="content-load-more-completed">
<%= render 'your_essays_completed', reservations_completed: #reservations_completed %>
</div>
<% unless #reservations_completed.current_page == #reservations_completed.total_pages %>
<div id="view-more-completed" class="center" style="min-width:100%;" >
<%= link_to('View More', url_for(page_completed: #reservations_completed.current_page + 1), remote: true, class: 'btn btn-back', style: 'min-width:100%;') %>
</div>
<% end %>
<div id="content-load-more-expired">
<%= render 'your_essays_expired', reservations_expired: #reservations_expired %>
</div>
<% unless #reservations_expired.current_page == #reservations_expired.total_pages %>
<div id="view-more-expired" class="center" style="min-width:100%;" >
<%= link_to('View More', url_for(page_expired: #reservations_expired.current_page + 1), remote: true, class: 'btn btn-back', style: 'min-width:100%;') %>
</div>
<% end %>
my_essays.js.erb:
$('#view-more-completed').click(function (event) {
$('#content-load-more-completed').append("<%=j render 'your_essays_completed', reservations_completed: #reservations_completed, format: 'html' %>");
});
<% if #reservations_completed.current_page == #reservations_completed.total_pages %>
$('#view-more-completed').remove();
<% else %>
$('#view-more-completed a').attr('href', '<%= url_for(page_completed: #reservations_completed.current_page + 1) %>');
<% end %>
$('#view-more-expired').click(function (event) {
$('#content-load-more-expired').append("<%=j render 'your_essays_expired', reservations_expired: #reservations_expired, format: 'html' %>");
});
<% if #reservations_expired.current_page == #reservations_expired.total_pages %>
$('#view-more-expired').remove();
<% else %>
$('#view-more-expired a').attr('href', '<%= url_for(page_expired: #reservations_expired.current_page + 1) %>');
<% end %>
partials for _your_essays_completed.html.erb and _your_essays_expired.html.erb:
<% reservations_completed.each do |reservation| %>
<!-- content -->
<% end %>
<% reservations_expired.each do |reservation| %>
<!-- content -->
<% end %>

Rails will_paginate two objects on the same page, passing one param from search field

I am using will_paginate on the results from two instance variables, each using the same param[:query] on two different PgSearch.multisearch methods. In the views, when clicking on one of the pagination links, both the tables were being updated. Is there any way to get around this problem? By passing only one param from the form? (As my search form has only one text field). I have searched and gone through the similar questions, most of them suggesting to use two params., but none of them gave me any thoughts to solve this prob using one param. :/
Code in the form:
<%= form_tag("/search", :method => "get", :remote => true) do %>
<%= label_tag(:query, "Search for: ") %>
<%= text_field_tag(:query, params[:query]) %>
<%= submit_tag("Search", class: "btn btn-primary") %>
<% end %>
Controller code:
def index
#employee = Employee.find(session[:user_id])
#search_employees = PgSearch.multisearch(params[:query]).where(:searchable_type => "Employee").paginate(page: params[:page], :per_page => 5)
#search_customers = PgSearch.multisearch(params[:query]).where(:searchable_type => "Customer").paginate(page: params[:page], :per_page => 5)
respond_to do |f|
f.html
f.js
end
end
Code in the View:
<% if !#search_employees.empty? %>
<h2>Employees</h2>
<table class="table table-hover">
.
.
<% #search_employees.each_with_index do |doc, index| %>
<% user = doc.searchable %>
<tr id="employee-<%= user.id %>">
.
.
<% end %>
</tbody>
</table>
<% end %>
<%= will_paginate #search_employees %>
<% if !#search_customers.empty? %>
<h2>Customers</h2>
<table>
.
.
</table>
<% end %>
<%= will_paginate #search_customers %>
Can I send two different params with the same text field value from the form? if so., please let me know how. Any ideas or suggestions would be much appreciated. :)
Thanks in Advance. :)
Pagination depends on the page parameter, but not on the query parameter from the search form, therefore you don't need to change anything in your form.
To update only corresponding table you need to customize page parameter in at least one of the tables. For example change page parameter for customers:
<%= will_paginate #search_customers, :param_name => 'customers_page' %>
and in controller:
#search_customers = PgSearch.multisearch(params[:query])
.where(:searchable_type => "Customer")
.paginate(:page => params[:customers_page], :per_page => 5)
This should resolve the issue

Rails - Dynamically Login People

I have a rails app and when user clicks to login button on header a bootstrap popup modal opens with a form, asks for user email and password. When user types and presses enter, I use window.location.reload(); and the button login turns in to a button with a text says "Welcome <%= current_user.name %>"
What I want to do is, instead of using window location reload, can I update this dynamically?
Here is my sessions#create action
def create
user = User.find_by(email: params[:session][:email].downcase)
respond_to do |format|
if user && user.authenticate(params[:session][:password])
if user.activated?
log_in user
params[:session][:remember_me] == '1' ? remember(user) : forget(user)
format.html { redirect_back_or user }
flash[:notice] = t('flash.sessions.create.success.html')
format.js #here I should do smth
else
format.html { redirect_to root_url }
format.json { render json: {email:['Account not activated. Check your email for the activation link.']} , status: :unprocessable_entity}
format.js { render json: {email:['Account not activated. Check your email for the activation link.']}, status: :unprocessable_entity }
end
then the create.js.erb
// close modal
$('#login-dialog').fadeToggle();
// clear form input elements
// todo/note: handle textarea, select, etc
$('form input[type="text"]').val('');
//Clear previous errors
$('.form-group.has-error').each(function(){
$('.help-block').html('');
$('.form-group').removeClass('has-error');
});
window.location.reload(); #here I am reloading the page then I can see login button disappears and new button saying Welcome Billy appears.
So how can I do that without reloading the window.
Thank you
EDIT
The thing is, I have also signup modal which user can click to open and these modal codes are in header.html.erb, when I render the page as you suggested it gives an error for sign up form;
<% modal ||= false %>
<% remote = modal ? true : false %>
<%= form_for(#user, remote: modal, :html => {role: :form, 'data-model' => 'user'}) do |f| %>
<div class="form-group">
<%= f.label :name, t('header.nameSurname') %>
<span class="help"></span>
<%= f.text_field :name, class: 'form-control' %>
<span class="help-block"></span>
</div>
<div class="form-group">
<%= f.label :username, t('header.username') %>
<span class="help"></span>
<%= f.text_field :username, class: 'form-control' %>
<span class="help-block"></span>
</div>
....
because of #user variable, if I change it to User.new is it ok?, would it create problem?.
I also have 3 different header partials. I normally render them in application.html.erb as;
<div id="render_main">
<% if #header_main %>
<%= render 'layouts/header_main' %> <!--Header comes here-->
<% elsif #header_listing %>
<%= render 'layouts/header_listing' %> <!--Header comes here-->
<% else %>
<%= render 'layouts/header' %>
<% end %>
</div>
But then in create.js.erb;
// close modal
$('#login-dialog').fadeToggle();
// clear form input elements
// todo/note: handle textarea, select, etc
$('form input[type="text"]').val('');
//Clear previous errors
$('.form-group.has-error').each(function(){
$('.help-block').html('');
$('.form-group').removeClass('has-error');
});
//window.location.reload();
<% if #header_main %>
$('#render_main').html('<%= j render "layouts/header_main"%>')
<% elsif #header_listing %>
$('#render_main').html('<%= j render "layouts/header_listing"%>')
<% else %>
$('#render_main').html('<%= j render "layouts/header"%>')
<% end %>
as I render it can not find #header_main variable I believe, so It does not work as it should be. How can I fix this?.
Main controller;
before_action :show_main_header, only: [:home]
def show_main_header
#header_main = true
end
Considering user login, from main controller home action. But it is probably because I actually run from session#create action. how can I fix it?
EDIT
firstly, thank you Rodrigo,
I have written a function to hold last action;
def location_action_name
if !logged_in?
url = Rails.application.routes.recognize_path(request.referrer)
#last_action = url[:action]
end
end
Then I write to create.js.erb;
<% if (#last_action == "home") %>
$('#render_main').html('<%= j render "layouts/header_main"%>')
<% elsif (#last_action == "listings") %>
$('#render_main').html('<%= j render "layouts/header_listing"%>')
<% else %>
$('#render_main').html('<%= j render "layouts/header"%>')
<% end %>
and worked! in case anyone wonders..
Let's say that you have an partial view for render the header (app/views/shared/_header.html.erb), what you need to do is rerender this partial and replace the header html:
create.js.erb
// window.location.reload();
$('#header-container').html('<%= j render "shared/header"%>')
EDIT:
If the #header_main and #header_listing variables are used to render the header partial, you'll need to instantiate them in your sessions#create action.
To do this, add the show_main_header filter to SessionsController too.

Rails: Populate inputs from a select tag in form

I'm running Rails 4 and Ruby 2.
I am creating an app where you can track your calories and macronutrients through each meal you eat.
I'm adding a meal favourites page where the user can add meals they consistently eat. I have done this through a favourites:boolean migration.
When a user creates a new meal I want to show them a drop down box of favourites they have already saved, by something like current_user.meals.where(favourite: true).
When they click on one of their favourites from the drop down I would then like that information to populate the protein, carbs and fat inputs in the form.
What is the best way to do this?
MealsController:
class MealsController < ApplicationController
.
.
.
def new
#meal = current_user.meals.build
end
def create
#meal = current_user.meals.build(meal_params)
respond_to do |format|
if #meal.save
format.html { redirect_to root_path, notice: 'Meal was successfully added.' }
else
format.html { render action: 'new', notice: 'Meal was not added.' }
end
format.js
end
end
.
.
.
private
def set_meal
#meal = Meal.find(params[:id])
end
.
.
.
end
New/Edit Meal Form
<%= form_for(#meal) do |f| %>
.
.
.
<div class="field inline">
<%= f.label :protein %> (g)<br>
<%= f.text_field :protein %>
</div>
<div class="field inline middle">
Carbs (g)<br>
<%= f.text_field :carbohydrates %>
</div>
<div class="field inline right">
<%= f.label :fats %> (g)<br>
<%= f.text_field :fats %>
</div>
<div class="field actions">
<%= f.check_box :favourite, class: "favourites" %> Add to Favourites?
</div>
<div class="actions">
<%= f.submit "Save", class: "btn btn-large" %>
<% if current_page?(edit_meal_path(#meal)) %>
<%= link_to "Delete", #meal, class: "btn btn-large", method: :delete, data: { confirm: "Are you sure?" } %>
<% end %>
</div>
<% end %>
Thanks!
You can do it with JavaScript/jQuery:
$(document).ready(function() {
bindFavoriteMeal();
});
function bindFavoriteMeal() {
$('#favorite_meal_select').change(function() {
var mealId = $(this).val();
var url = "/meals/" + mealId
$.getJSON(url, function(data) {
$.each(data, function(key, value) {
var field = $("#" + key);
if (field.length) {
field.val(value);
}
});
});
});
}
The show action in your meals controller will have to respond to JSON, and you need to ensure that the form ids match with the JSON keys returned. The JSON could look like:
{ 'name': 'Mustart Salmon', 'protein': 40, 'carbs': 8, 'other_stuff': 'some_value' }
See Rails Controller Overview: Rendering JSON.
The implementation of the select dropdown will depend on what it's for. Is it for associating an item from the dropdown with the object being created? In that case check out the other answer by #jordan-davis. Or is it merely to inform the user of previously made choices? In that case I'd recommend options_for_select. There are a lot of built-in helpers for selects:
ActionView Form Options Helpers
You would populate the dropdown with collection select
<%= collection_select :user, :meal, Meal.all, :id, :name, checked: meal.name.first %>
This code won't cut and paste, but it's to show the idea. After that, you would have to use jQuery to grab the meal id, and then use that to populate the rest of the info. You would start with something along the lines of:
$(".dropdown-menu li a").click(function(){
$(this).parents(".dropdown-menu:first").dropdown('toggle')
var selectedMeal = $(this).text();

AJAX micropost's comments on the user page

On the user's page there are microposts and each of them have it's own comment form and comments. Using "Endless Page" railscast i'm trying to create "show more comments" button, which will load comments by AJAX. But it's not working.
The problem is in show.js.erb file because:
1) common pagination of comments (without AJAX) is working well
2) "show more button" is working well too. I tested it on the users list page
I think "show more comments" not working because it don'understand <%= j render(comments) %> , <%= j will_paginate(comments) %> and i should have here variables like <%= j render(#comments) %> , <%= j will_paginate(#comments) %>.
But when i try to write in my users_controller.rb
def show
#micropost = Micropost.find(params[:micropost_id])
#comments = #micropost.comments
end
it's not working because on my user's page there are many microposts and i have an error "Couldn't find micropost without an id". So in my microposts/_micropost.html.erb i had to use this
<% comments = micropost.comments.paginate(:per_page => 5, :page => params[:page]) %>
<%= render comments %>
Can anyone please help? How should i change my show.js.erb?
users/show.html.erb
<%= render #microposts %>
microposts/_micropost.html.erb
...
micropost's content
...
<%= render 'comments/form', micropost: micropost %>
<% comments = micropost.comments.paginate(:per_page => 5, :page => params[:page]) %>
<div class="commentaries">
<%= render comments %>
</div>
<div id="append_and_paginate">
<%= will_paginate comments, :class =>"pagination", :page_links => false %>
</div>
javascripts/users.js.coffee
jQuery ->
if $('.pagination').length
$('#append_and_paginate').prepend('<a id="append_more_results" href="javascript:void(0);">Show more</a>');
$('#append_more_results').click ->
url = $('.pagination .next_page').attr('href')
if url
$('.pagination').text('Fetching more...')
$.getScript(url)
users/show.js.erb
$('.commentaries').append('<%= j render(comments) %>');
<% if comments.next_page %>
$('.pagination').replaceWith('<%= j will_paginate(comments) %>');
<% else %>
$('.pagination').remove();
<% end %>
<% sleep 0.3 %>
Bennington, in users/show.html.erb you have
But #microposts is not defined in your controller. What I think you want is to define #microposts as all the microposts associated with what, a User?
If so, you'd want something like `#microposts = Micropost.where(:user_id => current_user.id) or something.

Categories

Resources