I want something like this:
if has_route?(:controller => 'posts', :action => 'index')
...
How I can do this in a view?
---- SOLUTION ----
def has_route? options
Rails.application.routes.routes.map{|route| route.defaults}.include?(options)
end
I know this is sort of the inverse of what you want, but you can do something like this:
Rails.application.routes.recognize_path('/posts')
Which will return a hash like this:
{:controller=>"posts", :action=>"index"}
But i don't know of an API for giving it the hash and returning the path.
You could look through the ActionDispatch::Routing::RouteSet API.
Also, note that Rails.application.routes.routes returns an Array of Journey::Routes objects, so you could map this array for the controller/action pairing you want. But it seems like this API should already exist. If not, perhaps it should. :)
You could try something like respond_to?("[name of rails routing method]")
Usually the routes test in this way
it "routes to #index" do
get("/projects").should route_to("projects#index")
end
The scaffold for resource will generate the spec file for testing routes, for example you can look here
Related
I am successfully using the ":scopes =>" option of this gem to return a subset of the rows of the table. Now I want to create a nearly identical autocomplete, on the same ClassName and Method, with a different scope, for a different view.
The problem is, the first two arguments of autocomplete in the controller are ClassName and Method, and those also create the functional name of the autocomplete function, as it is used in the view and route. Therefore, both of my autocompletes would have the same name.
Is there a workaround I can use to assign a different name to each of the similar autocompletes?
Example code:
autocomplete :my_class_name, :my_method, :display_value => :my_formatting_method,
:extra_data => [:id], :scopes => [:active_and_special]
def active_and_special
where("active = ?", true).
where("special = ?", true).
order("name ASC")
end
Then the again for the 2nd one, with the same class-name and method, but a different scope.
Best workaround I've found is to use "column_name" to override the part of the naming which ordinarily refers to the method - like this:
autocomplete :my_class_name, :foo, :column_name => 'my_method',
:display_value => :my_formatting_method, :extra_data => [:id],
:scopes => [:active_and_not_special]
def active_and_not_special
where("active = ?", true).
where("special = ?", false).
order("name ASC")
end
This has route:
get 'my_class_names/autocomplete_my_class_name_foo'
Whereas the original has route:
get 'my_class_names/autocomplete_my_class_name_my_method'
This allows us to generate a 2nd, different autocomplete, on the same Class and Method as another, with its own unique name.
Having an independent name, vs the 'magic' autogenerated one (to save 1 second of typing?) would prevent this trouble - or am I missing something?
I'll leave this open for a bit to see if anyone has a better solution.
I've got a standard resourceful route setup for 'Invoice' however I'm looking to add in the ability to filter the invoice records based on their state.
/invoices - shows all invoices
/invoices/unpaid - shows all unpaid invoices
/invoices/paid - shows all paid invoices.
/invoices/3 - shows invoice #3
I've gotten this working no problem with an explicitly defined match route.
match "/invoices/pending" => "invoices#index", :state => 'pending'
However, with a growing number of possible states this means modifying the routes regularly, and also means I'm repeating myself quite a lot.
My next attempt was to make this route a little more dynamic with named params in the match route.
match "/invoices/:state" => "invoices#index"
However this then negates the /invoices/id route and trying to look for /invoices/3 finds no records as it's searching based on the state parameter.
Can anyone help with defining a filter route such as this that'll work dynamically?
Add regular expression as constraint in the routes:
match "/invoices/:id" => "invoices#show", :id => /\d+/
match "/invoices/:state" => "invoices#index"
It should select the only-number id-s for show, and the rest for the index.
Try to use routing constraints . Something like
match "/invoices/:id" => "invoices#show", constraint: { id: /\d+/ }
match "/invoices/:state" => "invoices#index", constraint: { state: /\w+/ }
I decided to take a slightly different route (excuse the pun) with this, by adding a constraint that rather then using REGEX used a method to look at possible states direct on the state machine.
# State based routes, which match the state machine dynamicly.
match "/invoices/:state" => "invoices#index", constraints: lambda { |r|
# Get an array if potential state names.
states = Invoice.state_machine.states.map &:name
# See if the request state name matches or not.
states.include?(r.params[:state].parameterize.underscore.to_sym)
}
# Resource routes go here.
This basically means that if I now go looking for /invoices/paid or /invoices/unpaid I get my expected index action, with the state variable set as expecetd.
However, doing something like /invoices/pay_soon which is not a valid event returns a 404.
Pretty happy with that solution, but thanks to the other suggestions which got me on to the track of using a constraint.
I'm trying to learn how to query a rails database and return the results as JSON. In my example, I want to query the data using the parameters, city and state.
So far, in my controller, I have gotten the following action to work.
def state
#bathrooms = Bathroom.where("state = ?" ,params[:state])
respond_to do |format|
format.json { render :json => #bathrooms }
format.js { render :nothing => true }
end
end
This is also my routing entry.
match '/bathrooms/state/:state',
:controller => "bathrooms",
:action => "state"
I can call this resource with the following URL:
http://localhost:3000/bathrooms/state/CA.json
That's all good but I don't know how to query by more than one parameter. Adding and AND clause in the controller seems to be easy enough.
BUT....I don't know how to
a.) Correctly write the routing entry?
b.) What would the URL look like if I tested it in a browser?
I've tried to understand rake routes but I must be missing something.
Could someone provide a basic example for what the action should look like? What the routing entry should look like and what does the URL to access the resource look like?
Again, if written in SQL, this is what I would like to be returned.
SELECT * from bathrooms WHERE city='Chicago' AND state = 'IL'
Any help appreciated.
You don't have to pass everything by the route - the URL also support GET parameters - those are the parameters you usually see after the question mark in the URL. You can add those GET parameters without changing your routes: http://localhost:3000/bathrooms/state/IL.json?city=Chicago. Then your can access the city parameter via params[:city]. but in your case, I think it will be better to use http://localhost:3000/bathrooms/index.json?state=IL&city=Chicago. You'll also need to change your routing to
match '/bathrooms/index',
:controller=>:bathrooms,
:action=>:index
and put the code in the index method of BathroomsController. You access the parameters the same - but the concept is different - you don't enter a state and look for bathrooms by city, you just look for bathrooms by state and city.
Anyways, you don't want to write the URL by hand - you want to a Rails helper or an HTML form generate it:
link_to "bathroom in Chicago, IL",:controller=>:bathrooms,:action=>:index,:state=>'IL',:city=>'Chicago'
If you want to use a form(to let the users choose their own state and city), you need to set it's method to GET:
form_tag {:controller=>:bathrooms,:action=>:index},:method=>:get do
and put state and city as fields.
It's also worth noting that while you can use SQL's AND to perform a search by multiple fields, you can also chain where methods: Bathroom.where(:state=>params[:state]).where(:city=>params[:city]).
You can put any arbitrary parameters in your querystring.
For example:
http://localhost:3000/bathrooms/state/CA.json?city=Chicago
your query looks like this:
#bathrooms = Bathroom.where("state = ? and city= ?" ,params[:state], params[:city])
Let's say I have a Rails 3 app that displays videos. The user can "Like" or "Dislike" the videos. Also, they can like/dislike other things like games. I need some help in the overall design and how to handle the RESTful routes.
Currently, I have a Like Class that uses polymorphic design so that objects are "likeable" (likeable_id, likeable_type)
I want to do this via AJAX (jQuery 1.5). So I was thinking something like:
javascript
// these are toggle buttons
$("likeVideo").click( function() {
$.ajax({
url: "/likes/video/" + video_id,
method: "POST",
....
});
} );
$("likeGame").click( function() {
$.ajax({
url: "/likes/game/" + game_id,
method: "POST",
....
});
} );
rails controller
Class Likes < ApplicationController
def video
# so that if you liked it before, you now DON'T LIKE it so change to -1
# or if you DIDN'T like it before, you now LIKE IT so change to 1
# do a "find_or_create_by..." and return JSON
# the JSON returned will notify JS if you now like or dislike so that the
# button can be changed to match
end
def game
# same logic as above
end
end
Routes
match "/likes/video/:id" => "likes#video", :as => :likes_video
match "/likes/game/:id" => "likes#game", :as => :likes_game
Does this logic seem correct? I am doing a POST via AJAX. Technically, shouldn't I be doing a PUT? Or am I being too picky over that?
Also, my controller uses non-standard verbs. Like video and game. Should I worry about that? Sometimes I get confused on how to match up the "correct" verbs.
An alternative would be to post to something like /likes/:id with a data structure that contains the type (game or video). Then I could wrap that in one verb in the controller...maybe even Update (PUT).
Any suggestions would be appreciated.
Rest architectural style does not specify which "verb" you should be using for what. It simply says that one can use HTTP if they want to for connectors.
What you are looking for is HTTP specifications for method definitions. In particular POST is intended for:
- Annotation of existing resources;
- Posting a message to a bulletin board, newsgroup, mailing list,
or similar group of articles;
- Providing a block of data, such as the result of submitting a
form, to a data-handling process;
- Extending a database through an append operation.
while PUT:
requests that the enclosed entity be stored under the supplied Request-URI. If the Request-URI refers to an already existing resource, the enclosed entity SHOULD be considered as a modified version of the one residing on the origin server.
Which category your functionality falls into is up to you - as long as you are consistent with yourself about it.
I'm aware that I can search queries by calling where() on a model as follows:
Post.where(:title => 'My First Post')
However, what if I don't know if the user wants to filter out the search parameters?
For example, I have a search form that has an optional title field. If the title is filled, the form should search for a title. If it is not, however, the form should just return all fields.
I tried doing something along the lines of
search = Post.all
if params[:title].present?
search.where(:title => params[:title])
end
However, Rails immidiately returns the result of the search when I call Post.all and I cannot further add conditions/
How do I do this?
Thanks!
.all is a 'finisher' method for arel and causes the query to actually be called (same goes for .each and .first). So, if you want to be able to keep building up the scope conditionally, .all should be the last thing called, if you want to call it at all.
Given that there really isn't much in the way of relations to chain here, it would seem that a simple one-liner with a ternary operator might do:
#posts = params[:title].present? ? Post.where(:title => params[:title]) : Post.all
... because when there is no :where clause scope, you couldn't later chain it to :all, anyway.