Kaminari and extra params - ruby-on-rails

I've looked around and I can't find anything close to answer for this. I think it's a pretty unique edge case though so I'm not surprised.
I have an index page where I'm showing all the leads, but I have 3 separate ways of showing it: unreviewed, reviewed, all. To accomplish this I use the current_page? helper, add: ?unreviewed=true to the url.
This worked no problem by itself, when I added in kaminari for pagination the page params seems to mess this up and make it so the current_page? cant read the extra params.
How can I fix this, or is there a better way to accomplish this goal?
This is using Rails 4 and Kaminari 0.15.1
Controller:
def index
#leads = Lead.order(:id).page params[:page]
#reviewed_leads = Lead.where(reviewed: true).order(:id).page params[:page]
#unreviewed_leads = Lead.where(reviewed: nil).order(:id).page params[:page]
current_page_no = Lead.page
end
index.html.erb
<tr>
<td colspan="7" style="text-align: center;">
<div class="pagination pagination-table">
<% if current_page?(controller: 'leads', action: 'index', unreviewed: 'true') %>
<%= paginate #unreviewed_leads %>
<% elsif current_page?(controller: 'leads', action: 'index', reviewed: 'true') %>
<%= paginate #reviewed_leads %>
<% else %>
<%= paginate #leads %>
<% end %>
</div>
</td>
</tr>
It worked when the URL looked like:
/closingloop/leads?unreviewed=true
with it like this, the current_page isn't reading it right and it's always showing the #leads instance variable
/closingloop/leads?page=2&unreviewed=true
any help would be greatly appreciated. I'm going to continue trying things. Will update with what I find.

Change your controller action to
def index
#leads = Lead.where(reviewed: params[:reviewed]).order(:id).page(params[:page])
end
Then in your view, you don't have to check for the current page, just make sure that you're passing the value of params[:reviewed]
<%= paginate #leads, params: { reviewed: params[:reviewed] } %>
UPDATE
As pointed out in the comments, this doesn't work for showing mixed leads. This can be achieved by creating a scope
# lead model
def self.filter_by_reviewed_status(status)
case status
when nil then scoped
when 'true' then where(reviewed: true)
when 'false' then where(reviewed: false)
end
end
Then in your controller, use this in getting the leads
#leads = Lead
.filter_by_reviewed_status(params[:reviewed])
.order(:id)
.page(params[:page])
Be sure to set params[:reviewed] to either true, false or nil (not pass at all) in links to get the leads you need

Related

How to show items which belong to the category

I'd like to answer what I'm doing wrong. So, I'm trying to list all products that belong to the category, on the category's page. Here is the code:
<% #product = Product.all%>
<% #product.where("category_id = ?", params[:#category_id]).each do |product| %>
<%= product.title %>
<%end%>
But there is nothing showing up on my page. So, what's wrong?
There is a whole bunch of problems with your code.
1) Read guides for starters.
2) You have to define an instance variable in controller's action, and then in view just use this variable in your loop. I assume, it is index action you have view for. If so,
def index
# this variable will be used in view
#products = Product.where(category_id: params[:id])
end
and then in view
#products.where(category_id: params[:category_id]).each..
Also, Make sure you have in params what you expect (inspect the params if not sure).
3) You do not execute code, so nothing is being output.
In erb to make things being evaluated you either use - or =. You used none of these. Here is how it should look like:
# notice dash at the beginning of the line
<%- #products.each do |product| %>
<%= product.category_id %>
<% end %>
probably you want read :category_id from params, not :#category_id (so it should be params[:category_id], not params[:#category_id]).

Variable scope in Rails 4 application

I'm learning rails and I have a test app in which I have listings and locations. There's a many-to-many relationship between them. My index page lists the listings, and provides (in construction) filtering functionality that includes checking locations. This is (partially) done with this, in the index.html.erb file:
<ul class = "list-inline">
<% #locations.each do |location| %>
<li> <label class="checkbox"> <input type="checkbox" value="<%= location.id %>" id="inlineCheckbox1"> <%= location.name %> </label></li>
<% end %>
</ul>
It does the job of displaying all locations with a checkbox to the left of each name.
Now, when adding or editing a listing, I need to let the user select which locations, apply to the listing, so I follow the same idea, and in the _form.html.erb file I have the following code as part of the form:
<select class="multiselect" multiple="multiple">
<% #locations.each do |location| %>
<option value="<%=location.id%>"><%=location.name%></option>
<% end %>
</select>
But this time, I get the following error, whenever going to the new or edit pages:
undefined method 'each' for nil:NilClass
with the
<% #locations.each do |location| %>
line being highlighted.
What am I missing?
(I have omitted code that I thought is irrelevant for the issue in order to now overwhelm you, but I may be wrong).
SOLUTION
Thanks for jumping in with your answers. Sorry I couldn't reply before, as I was at work and without access to my code.
I feel very sheepish... I was missing what is now obvious. The code for my New and Edit actions in the controller needed to have:
#locations = Location.all
Most of you said that in one way or another. I had to choose one answer and I did the one that appeared to me as the most straightforward, being also in comments on the question itself. Thanks!
Please double check your action to make sure you have the # variable in your action. I imagine it should be like this
#listing = Listing.find(params[:id])
#locations = #listing.locations
Your #locations is set in your index action, but it does't live forever. Just long enough for the index page to render. You can either set it again in your edit action, or just change your code to this:
<% Location.all.each do |location| %>
You might not be setting your #locations in your new action.
You can set it like this:
#locations = Location.all
In this case, however, I would like to recommend using a collection_select:
<%= f.collection_select(:location, Location.all, :id, :name, {multiple: true})%>
Local Vars
The problem, without seeing your controller or model, will be with your use of a partial
Rails partials don't use the same #instance variables as their parent views - you have to pass local vars to them (probably because they're designed to be used in many parts of an app; consequently passing local vars keeps them consistent):
#Parent
<%= render partial: "form", locals: { locations = #locations } %>
#_form.html.erb
<% locations.each do |location| %>

Ruby on Rails: Record Creation from view error

I have an isolated issue.
I have a table that populates from several different models, it creates links to follow to each respective view.
The code that I have made for each link should be the same, but for some reason, the link isn't showing up under 'Baseline'. I've checked the :create methods for each model, and they mimic each other, and the code from the view is also just a copy - so I'm at a loss as to where to look next. I'm sure that the problem is that the create method is failing, but I don't know where/how.
Here is the code from my view (I'm also pasting the code from FollowUp3Week, because it works):
<% if Baseline.where(subject_id: sub.subject_id).first != nil %>
<%= link_to "edit", baseline_path([Baseline.where(subject_id: sub.subject_id).first]) %>
<% else %>
<%= Baseline.create(subject_id: sub.subject_id) %> #I left the equal for the screenshot.
<% end %>
</td>
<td>
<% if FollowUp3Week.where(subject_id: sub.subject_id).first != nil %>
<%= link_to "edit", follow_up3_week_path([FollowUp3Week.where(subject_id: sub.subject_id).first]) %>
<% else %>
<% FollowUp3Week.create(subject_id: sub.subject_id) %>
<% end %>
</td>
And here is the create method from baselines_controller.rb
def create
#baseline = Baseline.new(params[:baseline])
if #baseline.save
flash[:success] = "Baseline added from create method"
redirect_to baselines_url
else
render 'new'
end
end
I'm also attaching an image of what it looks like. If I remove the equal sign from <%=, the cell will be blank.
EDIT. I'm in the process of removing all of my database queries from the view. Thank you for your comments.
You should really get that Baseline.where out of your view and into the model. AR scopes from the view is a serious no-no in Rails.
In your baseline mode you could do something like:
def empty_subject(subject_id)
where(subject_id: subject_id).first != nil
end
Also, it looks like you're passing arrays into baseline_path and follow_up3_week_path.
Ditch the square brackets.
on Baseline model, put this
def display_name
"#{name}" #whatever you like to show including link
end

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.

dealing with complex GET params in rails

I'm trying to pass params via GET to a form using ransack, it would normally work fine except that the params[:q] is causing a problem when I try to merge it.
controller (using ransack)
def index
#search = Record.ransack(params[:q])
#records = #search.result.page(params[:page])
end
view
<ul>
<% Genre.all.each do |genre| %>
<% category_count = #search.result.joins(:genre).where("genres.id = ?", genre.id).size %>
<% unless category_count == 0 %>
<li>
<%= link_to genre.name, params.merge(:"q[genre_name_eq]" => genre.name) %> (<%= category_count %>)
</li>
<% end %>
<% end %>
</ul>
But I keep getting duplication:
q[genre_name_eq]=Rockabilly&q[genre_name_eq]=Rockabilly
Without the q[] it manages the params correctly, overwriting the previous one.
Also tried params[:q].merge(:genre_name_eq) which causes the problem when there is no q[] and it also just doesn't work, giving me genre_name_eq= and no q[]
How else can I handle the q[] so that it replaces the value instead of duplicating it several times?
EDIT (after your edit)
params is a hash, not a simple querystring. If you want to update a nested value, you have to update the nested hash.
First ensure that params[:q] exists and is a hash (in the controller)
params[:q] ||= {}
Then only update q in the view
<% params[:q].update :genre_name_eq => genre.name %>
<%= link_to genre.name, params %>

Resources