Rails use the same endpoint instead of two new - ruby-on-rails

In my app I need to display purchased Book in one page and planned_purchase Book in other page. The view will be the same so my question is - do I need to create new controller method and routes to display both or can I use e.g. Index and somehow display two different values depending on request?
current code below:
class BooksController < ApplicationController
before_action :fetch_conversation
def index
#planned = Book.planned_purchase
#purchased = Book.purchased
end
end
class Book < ApplicationRecord
scope :purchased, -> { where(purchased: true) }
scope :planned_purchase, -> { where(purchased: false) }
end

As I can understand: you can do this thing using a single controller GET action.
So, you've this BooksController and index action, which I assume can be accessible via books_path.
You can modify the index method, as follows to accept a new parameter by which you can filter the books:
def index
case params[:filter]
when 'purchased'
#records = Book.purchased
when 'planned_purchase'
#records = Book.planned_purchase
else
#records = Book.all
end
end
Now, you have a view page books/index.html.erb for this index action. Let's break this into 2 separate partials.
In books/index.html.erb:
<% if params[:filter] == 'purchased' %>
<%= render "partial_for_parchased" %>
<% elsif params[:filter] == 'planned_purchase' %>
<%= render "partial_for_planned_parchased" %>
<% end %>
Inside those partials you can modify the view based on the category.
Now, to get those two different page, you need to define 2 separate urls:
<%= link_to 'Purchased', books_path(filter: 'purchased') %>
<%= link_to 'Planned Purchased', books_path(filter: 'planned_purchase') %>
As your, def index, is a GET method and not depending on the strong parameters, so you don't need to add filter in your params.required(:book).permit(...)
Hope I covered all the areas!

I think the answer should be pretty simple and straight.
You can just pass a parameter to the index method and filter records inside it and return them.
def index
case params[:filter]
when 'purchased'
#records = Book.purchased
when 'planned_purchase'
#records = Book.planned_purchase
else
# get all records or throw an error
end

Related

How to filter by params and user input in Rails

I am trying to display only the rows that belong to certain states in my application. I can do it the long way in Javascript, but I would prefer to better understand Rails and queries in the controller. I want to take the users to another page and then show them only that the companies in that state. It would be great to not have to link them to another page. Does anyone know how to do this?
Here is what I have in my controller
def vendors
#vendors = Collective.where(sort: 'Vendor').all
#vendors = #vendors.where(params[:state])
end
My route
get '/vendors/:state', to: 'collectives#vendors'
Then I use the stereotypical method to print a table in a html.erb file.
<% #vendors.each do |company| %>
<tr>
<td><%= company.name %></td>
<td><%= company.state %></td>
etc...
Should your controller code change the where as follows:
def vendors
#vendors = Collective.where(sort: 'Vendor').all
#vendors = #vendors.where(state: params[:state])
end
or better:
def vendors
#vendors = Collective.where(sort: 'Vendor', state: params[:state])
end
Using sessions instead of url params.
This is more or less what you can do, sorry if it is not completly working for your case, just to give an idea.
# view collectives/index (or whatever you have)
<%= form_tag (controller: :collectives, action: :set_status_filter, method: :post) do %>
<%= select_tag(:session_status_filter, options_for_select(#your_list_of_options_for_the_filter)) %>
<%= submit_tag "Set filter" %>
<% end %>
# collectives controller
def index # or whatever, this is the page containing the form and the list to show
#vendors = Collective.where(sort: 'Vendor').all
if session[:session_status_filter] == # etcetera
then #vendors = #vendors.where(state: session[:session_status_filter]) # for example
else # another option just in case, etcetera
end
end
def set_status_filter # this action is called by the form
session[:session_status_filter] = params[:session_status_filter]
respond_to do |format|
format.html { redirect_to *** the view where the form is placed ***, notice: 'the filter is set to: ....' + session[:session_status_filter] } # after the session variable is set the redirects goes to index which uses the session to filter records
end
end
params[:session_status_filter] is passed by the form to collectives#set_status_filter. The value is used to set the session variables. After that the action collectives#set_status_filter redirects to the index, or whatever page you placed the form and the list to show.

rails link_to - pass hash of values to controller action

I have retrieved some records based on condition in a hash - #special_products. Now I want to pass the hash to a non-restful action(:special)/ of the same controller so that I can view the products.
I've tried this but how can link_to pass hash and how should the value be retrieved in action: special? which is in the same products_controller?Many thanks.
products_controller.rb
def show
#special_products = Product.by_company
end
show.html.erb
<%= link_to "Special Products", special_path(:anchor => "#{#special_products}") %>
If you're hitting the show action of the Products controller, you should be showing a product.
If you want to show a product in a special way, use the same show action, but render a different view for it.
def show
#product = Product.find(params[:id])
render #product.special? ? 'special_show' : 'show'
end
If you want to list some products in a different way (a filtered collection), you want to use an index. E.g. the products#index action.
def index
#products = Products.not_special
#special_products = Products.way_special
end
# app/views/products/index.html.erb
Special Products:
<%= #special_products.pluck(:name).to_sentence %>
Finally, note that the parameters you pass to link_to end up in the linked URL, which means that your example link_to is going to render something like #<Array []> in the href attribute.

Rails Call A Method Lastly In Action

I have something like that in my controller:
def index
#votes = Vote.all
end
private
def search
#votes = OtherVotes.all
end
I want to use search method in index action but I don't want to remove my #votes variable from index. If I use before_action, it calls method before the action so #votes doesn't change. Is it possible to call search method after my votes variable or ignore the variable without removing.
I normally go with this method when I'm looking to build a simple search:
http://railscasts.com/episodes/37-simple-search-form
Create a method in your vote.rb file:
class Vote
def self.search(search)
if search
self.where(:all, conditions: ['name LIKE ?', "%#{search}%"])
else
self.where(:all)
end
end
end
This means when you do Vote.search('term'), you'll bring up any records with a similair name. Replace name for whatever term you're searching for (i.e. title or category).
If there is no search term entered this method simply returns every instance. This means you can leave your controller looking like this:
def index
#votes = Vote.search(params[:search])
end
Finally the view for this would be something like:
<% form_tag votes_path, :method => 'get' do %>
<p>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", :name => nil %>
</p>
<% end %>
This will send a get request to the votes_path (the index action on your controller), with the search term parameter. If one is entered the search will return the relevant instances, and if not it will return all.
Try
class TempController < ApplicationController
after_action :search
def index
#votes = Vote.all
end
private
def search
#votes = OtherVotes.all
end
end

Rails: Detect if current page ends in "/foo"

How would you detect if the current page ends in ".foo" in Rails?
Basically, I'd like to show different things in my view based on what's passed in the url.
Something like <% if !current_page?('something/something/foo') %> but more dynamic
In Rails 3.2+:
# in your controller
url = request.original_url
#ext = File.extname(url) #=> .foo
# in your view
<% if #ext == '.foo' %>
# do this
<% else %>
# do that
<% end %>
In Rails 3:
# to retrieve the fully qualified URL
url = "#{request.protocol}#{request.host_with_port}#{request.fullpath}"
I'm assuming you're talking about responding with different things depending on the file type requested. Typically, this is what respond_to is for:
class SomeController < ApplicationController
def some_action
respond_to do |format|
format.html { render :new }
format.foo { render :foo }
end
end
end
Otherwise if you really want to just do stuff inside the view, do what zeantsoi showed. This is just kind of irregular. If I knew more about the use case I'd be better able to answer your question.
you can find here how to get full url switch rails version you are using, then after get this url you just need to split it with / then get the last element with .last like this :
url.split("/").last
i think this is the easy way

How do i impliment pagination here (only for the next pages)

How would i implement pagination in this case.. I am using a gem that already calculate the next pages. #client.videos_by(:tags=>{:include=>[:cover,:acoustic]},:page=>2) (page is method from the gem that accept page number) This query returns array of videos in the second page only, if i substitute with 3 it is going to return the third page only.How do i implement the next page? This is what i tried but when i click next it keeps returning the first page every single time.
Controller
class StarsController < ApplicationController
##current||=1
def index
#videos=#client.videos_by(:tags=>{:include=>[:cover,:acoustic]},:page=>##current)
end
def next
##current+=1
redirect_to :action=>'index'
end
end
View
<%= link_to "next",:controller=>"stars",:action=>"next" %>
The class variable (##current) is a bad idea because it is shared among all users.
You can simply use a parameter with the index method:
class StarsController < ApplicationController
def index
#page = params[:page] || 1
#videos = #client.videos_by(:tags=>{:include=>[:cover,:acoustic]},:page=> #page)
end
end
In the view
<%= link_to "next", :action=>"index", :page => #page + 1 %>

Resources