Rails: will_paginate + simple search engine error: undefined method `total_pages' - ruby-on-rails

on my users index page I am trying to have a search engine at the top so that you can search a user by email instead of scanning through the whole list. However, I am getting the error:
undefined method 'total_pages'
when I search any term.
Can anyone help? Thanks!
users/index.html.erb
<h1>All users</h1>
<%= form_tag users_path, :method => "get" do %>
<%= label_tag(:search, "Search for user by email:") %>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", :name => nil %>
<% end %>
<%= will_paginate #users %>
<br>
<% #users.each do |user| %>
<div>
<%= link_to (image_tag user.profilepic? ? user.profilepic : "questionmark.png", :size => "50x50"), user_path(user) %>
<%= link_to user.name, user_path(user) %> (<%= user.email %>)
<% unless current_user.friends.include?(user) || current_user == user %>
<span class="floatright"><%= link_to "Add friend", user_friends_path(:user_id => current_user.id, :friend_id => user.id), :method => :post %></span>
<% end %>
<% if current_user.friends.include?(user) %>
<span class="floatright"><%= link_to "Remove friend", user_friends_path(:user_id => current_user.id, :friend_id => user.id), :method => :delete, :confirm => "Are you sure you want to remove #{user.name} from your friends?" %></span>
<% end %>
</div>
<% end %>
users controller
def index
if params[:search]
#users = User.search(params[:search])
else
#users = User.order("email").page(params[:page]).per_page(10)
end
end
user model
def self.search(search)
find(:all, :conditions => ['email LIKE ?', "%#{search}%"])
end

You're not calling a pagination method in #users = User.search(params[:search]). Try adding the .page(params[:page]).per_page(10) and see if that works.
UPDATE:
Sorry, I forgot .find returns an array and not a relation. Change your search method to this:
def self.search(search)
where('email LIKE ?', "%#{search}%")
end

Related

Undefined method 'each' for nil:NilClass, for #topics

I am trying to display a content on a page. I have:
index.html.erb
<if !user_signed_in? %>
<%= link_to 'Download Topics', resumes_url, :class => 'btn btn-danger' %>
<%= form_tag topics_path, :method => 'get' do %>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search" %>
<% end %>
<% #topics.each do |topic| %>
<div class="topic">
<h3><%= topic.title %></h3>
<p><%= topic.id %></p>
<p class="text-justify" ><%= topic.body %></p>
<p><%= topic.date %></p>
<%= image_tag topic.image.url, class: "topic-show" if topic.image? %>
</div>
<% if current_user && current_user.admin? %>
<%= link_to "Edit", edit_topic_path(topic), :class => 'btn btn-default' %>
<%= link_to "Destroy", topic, :class => 'btn btn-default', method: :delete, data: {confirm: 'Are you sure?'} %>
<% end %>
<%= link_to "Show", topic_path(topic), :class => 'btn btn-default' %>
<% end %>
<div>
<%= will_paginate #topic, renderer: BootstrapPagination::Rails %>
</end>
topics_controller.rb, index action
class TopicsController < ApplicationController
before_action :authenticate_user!, except: [:show, :index, :update, :destroy]
def index
#topics = Topic.search(params[:search]).paginate(:page => params[:page], :per_page => 5
#topics = Topic.all
end
end
And I received an error
undefined method `'each'` for `nil:NilClass`
The error is thrown at <% #topics.each do |topic| %>.
I am unsure what to do. I have tried to add:
#topics = Topic.all
to topics#index, but that does not seem to resolve the issue.
This error just means that #topics is empty.
To troubleshoot this, you need to refresh the page while watching your console.
Examine the queries being ran when these lines run:
#topics = Topic.search(params[:search]).paginate(:page => params[:page], :per_page => 5
#topics = Topic.all
If you can't spot the issue in the console, copy the query into your database GUI and run the query, modify it till you get your expected results and edit the query.
I would assume that your issue might have to do with the params being passed.
You should add this before your queries to view what params you are picking up.
p 'my params'
p params[:search]
p params[:page]
PS. I suggest making your per_page a variable, it makes it easier when going through code to see all the hard coded values and change them when they are not in the middle of a code block.

Search Form with Rails:When I type in full email or username, results don't come back

I'm trying to make a search form with Ruby on Rails. Part of it is successful and part of it is not. If i type in a part of the usernames of emails I have registered, results come back. But when I type in the full username of a user, no results come back. Here is my user.rb file:
def self.search(search)
where("username LIKE ?", "%#{search}%")
where("email LIKE ?", "%#{search}%")
end
My search_controller.rb:
def index
#users = User.all
if params[:search]
#users = User.search(params[:search]).order("created_at DESC")
else
#users = User.all.order('created_at DESC')
end
end
And finally my view:
<%= form_tag(search_path, :method => 'get', id: 'search-form') do %>
<%= text_field_tag :search, params[:search], placeholder: "Search Users" %>
<%= submit_tag "Search", :name => nil %>
<% end %>
<% if params[:search].present? %>
<% if #users.present? %>
<h1><li>Search Results for: "<%= params[:search] %>":</li></h1>
<% #users.each do |user| %>
<li><%= user.username %></li>
<li><%= user.email %></li>
<br />
<% end %>
<% else %>
<p>There are no users with the term(s) <%= params[:search] %>.</p>
<% end %>
<% else %>
<title>Search Users</title>
<% end %>
Your method only returns the result of the second where. To fix this combine both queries into one:
def self.search(search)
where('username LIKE :query OR email LIKE :query', { query: "%#{search}%" })
end

link submit to another page

I have this form:
in header of my website:
<% form_tag request.path, :method => 'get' do %>
<p>
<%= text_field_tag :query, params[:query] %>
<%= submit_tag "Search User", :name => nil %>
</p>
<% end %>
controller:
def index
#title = "All users"
#users = User.paginate(:page => params[:page])
#users1 = User.simple_search(params[:query]).all
end
model:
acts_as_simply_searchable :columns => [:name, :email]
view
<%= will_paginate %>
<ul class="users">
<%= render #users1 %>
</ul>
<%= will_paginate %>
displays a user
I want to link the submit button to index.html.erb (i have assigned a path in routes.rb). So that the user can look at the search results
You don't do this at the submit button, but at the form_tag URL (the first parameter). It would be something like this:
<% form_tag users_path, :method => 'get' do %>
<p>
<%= text_field_tag :query, params[:query] %>
<%= submit_tag "Search User", :name => nil %>
</p>
<% end %>
Simply change request.path to the desired path.
I think you are missing the '=' sign and string interpolating the 'request.path'
This Worked for me:
<%= form_tag "#{request.path}", method: "get" %>
...the rest of your code ...
<% end %>

Ruby/Rails Conditional search method (if ... else "no results found")

Here is the code of a "simple search form" (thanks to jordinl) which I try to improve. I would like to add the case if there is no match found.
So, there is the view (views/users/index.html.erb)
<% form_tag users_path, :method => 'get' do %>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", :name => nil %>
<% end %>
<% #users.each do |user| %>
<p><%= link_to "#{user.name}", user %></p>
.
.
.
<% end %>
The controller ( users_controller.rb)
def index
#users = User.search(params[:search])
end
and the method in user model:
def self.search(search)
search.blank? ? [] : all(:conditions => ['name LIKE ?', "%#{search.strip}%"])
end
I tried the following:
def self.search(search)
if search.to_s.size < 1
[]
else
if #users.size > 0
all(:conditions => ['name LIKE ?', "%#{search.strip}%"])
else
render :text => "No result found"
end
end
end
reporting the following error: "You have a nil object when you didn't expect it!..." (no instance in the array). Then, I tried to add
<% if #users? %>
<% #users.each do |user| %>
.
.
.
In the view. But it doesn't work either.
I would be pleased to understand why I'm wrong on this. Thank you!
You're on the right track. Try this:
<% if (#users) %>
<% if (#users.empty?) %>
<p>No users found.</p>
<% else %>
<% #users.each do |user| %>
<p><%= link_to "#{user.name}", user %></p>
<% end %>
<% end %>
<% else %>
<p>Use the search form to search for stuff.</p>
<% end %>
Change your search method to only return something if searching was used:
def self.search(search)
search.present? and all(:conditions => [ 'name LIKE ?', "%#{search.strip}%" ])
end
you can't render in your model.
In your view:
<% form_tag users_path, :method => 'get' do %>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", :name => nil %>
<% end %>
<% if #users.empty? %>
No records found!
<% else %>
<% #users.each do |user| %>
<p><%= link_to "#{user.name}", user %></p>
<% end %>
<% end %>
In your model:
def self.search(search)
search.blank? ? [] : all(:conditions => ['name LIKE ?', "%#{search.strip}%"])
end
You are close with your check on #users? but it should be:
<% if !#users.empty? %>
<% #users.each do |user| %>
...
<% end %>
<% else %>
No users found.
<% end %>
This will work with your original self.search implementation which, correctly, is used just to find users and does not need to worry about reporting if none are found.
Your self.search method should return an array, either full or empty. Try:
in you model
def self.search
self.all(:conditions => ['name LIKE ?', "%#{search.strip}%"])
end
and in your view
<% if #users? %>
<% #users.each do |user| %>
…
<% end %>
<% else %>
No result
<% end %>

How can I refactor these unless statements to make the block more efficient?

I'm trying to add a "current" class to the following set of links based on if there is an "order" param in the URL. (ie. example.com/photos?order=views). I need some help refactoring this so it's not so burly.
<% unless params[:order] != 'created_at' %>
<%= link_to "Recently Posted", photos_path, :class => 'current' %>
<% else %>
<%= link_to "Recently Posted", photos_path %>
<% end %>
<span class="pipe">|</span>
<% unless params[:order] != 'comments' %>
<%= link_to "Most Commented", photos_path + "?order=comments", :class => 'current' %>
<% else %>
<%= link_to "Most Commented", photos_path + "?order=comments" %>
<% end %>
<span class="pipe">|</span>
<% unless params[:order] != 'views' %>
<%= link_to "Most Viewed", photos_path + "?order=views", :class => 'current' %>
<% else %>
<%= link_to "Most Viewed", photos_path + "?order=views" %>
<% end %>
For example you can use helper:
<%= link_to_photos_with_order 'created_at', "Recently Posted" %>
<span class="pipe">|</span>
<%= link_to_photos_with_order 'comments', "Most Commented" %>
<span class="pipe">|</span>
<%= link_to_photos_with_order 'views', "Most Viewed" %>
def link_to_photos_with_order order_by, title
url = photos_path(:order => (order_by != 'created_at' ? order_by : nil))
unless params[:order] != order_by
link_to title, url, :class => 'current'
else
link_to title, url
end
end
Another way is to use hash with order_by => title but it is uglier
Extract the logic into a helper:
def link_to_ordering(params, ordering, title)
css_class = params[:order] == ordering ? 'current' : ''
link_to(title, photos_path(:order => ordering), :class => css_class)
end
Then just call e.g.:
<%= link_to_ordering(params, "Most Commented", "comments") %>
in your views.

Resources