Rails: Detect if current page ends in "/foo" - ruby-on-rails

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

Related

Routing to different instances of Index using a Helper Method

I have a controller called BookingsController with a bookings#index action. Inside the index action, there are 2 instance variables, #pending_bookings and #approved_bookings, which query Booking objects by their status.
def index
#pending_bookings = Booking.where(host_id:#user.id,
status:'pending')
#approved_bookings = Booking.where(host_id:#user.id,
status:'approved')
end
I want to route the user to a different instance of index depending on the link they click. Basically bookings_path(#pending_bookings) should route the user to the index page displaying all pending_bookings, adversely, bookings_path(#approved_bookings) should route the user to the index page displaying all approved_bookings.
In my view, I have 2 links that should direct the user to each path respectively.
<%= link_to 'Pending Reservations', bookings_path(#pending_bookings)%>
<%= link_to 'Approved Reservations', bookings_path(#approved_bookings)%> `
The index.html.erb file:
<%= booking_index_helper_path %>
contains an embedded helper method that should recognize the path the user clicks and render the proper Booking objects.
Here's the (flawed) logic for recognizing the path the user chooses and rendering the necessary objects:
pages_helper.rb:
def booking_index_helper_path
if bookings_path(#pending_bookings)
render #pending_bookings
elsif bookings_path(#approved_bookings)
render #approved_bookings
else bookings_path(#total_bookings)
#total_bookings
end
end
I put a binding.pry in the helper method to confirm it is being hit (it is). For some reason when I click the link to direct me to the proper objects, however, the first condition is always satisfied. What is a better way to write this conditional to recognize the path the user chooses?
It seems like you're going about this in a more complicated way than you need to. Why not just have an index like:
def index
#Rails autoescapes this string so no fear of sql injection using user supplied strings
#bookings = Booking.where(host_id:#user.id, status: "#{params[:status]}")
end
Then use a link like:
<%= link_to 'Pending Reservations', bookings_path(status: 'pending')%>
<%= link_to 'Approved Reservations', bookings_path(status: 'approved')%> `
Now your view can just handle #bookings and not concern itself with the types of #bookings as that is done by the logic in your controller. This is the bare minimum but you should get in the habit of adding error messages etc. to your controllers so consider doing:
def index
if params[:status].present?
#Rails autoescapes this string so no fear of sql injection using user supplied strings
#bookings = Booking.where(host_id:#user.id, status: "#{params[:status]}")
flash[:success] = "#{params[:status].titleize} Bookings loaded."
redirect_to whatever_path
else
flash[:error] = "Something went wrong"
redirect_to some_path
end
end

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.

Using if .present? redirect

I feel like this is simple but I'm banging my head against the wall. I'm trying to tell my Rails app that if one parameter is present (signature in this example) that I want to redirect home. Here's my code:
<%= if #pc.signature.present? %><% redirect_to "pages#home" %><%end%>
I keep running into a syntax error. This is in the edit.html.erb file by the way.
Perhaps in your controller you didn't define #pc? also, use path instead of 'pages#home'. it should look more like this:
def edit
#pc = Pc.find(params[:id]) #or whatever your logic is
redirect_to root_path if #pc.signature.present?
# otherwise 'edit' template will be rendered
end
You need to do that on your action controller, not in the view
def your_action
if #pc.signature.present?
redirect_to 'your_path_or_url'
end
end

Redirecting to different actions without using a query string

I am trying to figure out the best way to do the following (there are a few ways I can think of, but I want to know what the best way to handle it is):
A user is putting together a shipment, and then clicks the "Send" link, which sends him to the /shipments/:id/confirm page. The confirm action checks to see if the user has a completed ShippingAddress; if not, it sends him to the ShippingAddress#new. (If he does, it render the confirm page.
I want the user to be able to complete the ShippingAddress#new page, submit it, and then be redirect back to the /shipments/:id/confirm. How can I do that? How can I pass the :id to the ShippingAddress#new page without doing something like redirect_to new_shipping_address_path(shipment_id: #shipment.id) in the Shipment#confirm action? Or is that the best way to do that?
class ShipmentsController < ApplicationController
def confirm
#shipment = Shipment.where(id: params[:id]).first
unless current_user.has_a_shipping_address?
# Trying to avoid having a query string, but right now would do the below:
# in reality, there's a bit more logic in my controller, handling the cases
# where i should redirect to the CardProfiles instead, or where I don't pass the
# shipment_id, and instead use the default shipment.
redirect_to new_shipping_address_path(shipment_id: #shipment.id)
end
end
end
class ShippingAddressesController < ApplicationController
def new
#shipment = Shipment.where(id: params[:shipment_id]).first
end
def create
#shipment = Shipment.where(id: params[:shipment_id]).first
redirect_to confirm_shipment_path(#shipment)
end
end
[In reality, there is also a CardProfiles#new page that needs to be filled out after the shipping address is].
Try calling render instead of redirect_to, and set the id into an instance variable. Adjust the view logic to pull that instance variable if it exists.
#shipment_id = #shipment.id
render new_shipping_address_path
In the view
<%= form_for #shipment_address do |f| %>
<% if #shipment_id %>
<%= hidden_field_tag :shipment_id, #shipment_id %>
<% end %>
I don't know your view logic entirely, but giving an example.

link_to_unless_current fails when processing forms with error messages in it with restfull routes

does anyone know how to prevent the failing mechanism of link_to_unless_current?
f.e.: I have my page navigation with
link_to_unless_current "new task", new_task_path
When I click on the link, i come to the new taks path form... And no link is created -> ok.
Then I put incorrect values in the form and submit.
The TasksController processes the "create" action, the validation for the ActiveRecord-model fails because of the incorrect data and the controller renders the "new" action (and includes the error messages for the model).
class TasksController < ApplicationController
def create
#task = Task.new(params[:task])
if #task.save
flash[:notice] = 'task was successfully created.'
redirect_to(tasks_url)
else
render :action => "new"
end
end
end
But here the link gets created!
-> Because of the difference between the urls:
link path = new_task_path
but
posted path = tasks_path with :method => :post
Does anybody know how to cleanly solve this problem?
Thanks
Having a quick look at the source for link_to_unless_current...
...it makes use of current_path? such that you should be able to do something like this:
In a helper...
def current_page_in?(*pages)
pages.select {|page| current_page?(page)}.compact.any?
end
... and then in your view, you can just supply an array of either named_routes or hashes like Shadwell's answer above.
<%= link_to_unless(current_page_in?(new_thing_path, things_path), "add a thing") %>
You get the idea...
UPDATED
Had a think about this... and it'd be great if you could just use it like you'd hoped that the original method worked. Here we compare the supplied named route (or controller + action hash) with the current page AND its referrer.
def current_page_or_referrer_in(options)
url_string = CGI.unescapeHTML(url_for(options))
request = #controller.request
# We ignore any extra parameters in the request_uri if the
# submitted url doesn't have any either. This lets the function
# work with things like ?order=asc
if url_string.index("?")
request_uri = request.request_uri
referrer_uri = request.referrer
else
request_uri = request.request_uri.split('?').first
referrer_uri = request.referrer.split('?').first
end
#referrer_uri always has full path (protocol, host, port) so we need to be sure to compare apples w apples
if url_string =~ /^\w+:\/\//
["#{request.protocol}#{request.host_with_port}#{request_uri}", referrer_uri].include?(url_string)
else
referrer_uri = referrer_uri.gsub(request.protocol, '').gsub(request.host_with_port, '')
[request_uri, referrer_uri].include?(url_string)
end
end
The beauty is that it now lets you just do this (from your example):
<%= link_to_unless(current_page_or_referrer_in(new_task_path), "Add a task") %>
It'll then display if you're on new_task_path OR a page to which it has been sent (such as the create page
You can do it with link_to_unless instead of link_to_unless_current:
link_to_unless(controller_name == 'tasks' &&
(action_name == 'new' || action_name == 'create'),
new_task_path)

Resources