I am new to writing rails applications. I am using Rails 4.2.0 with Ruby 2.0.0p598.
I have modified the cascading select implementation found here and used it to create new Products (has model and main controller) linked to Productgroups and Productsubgroups (both have their models, but no controllers) as the cascade levels. The implementation employs some javascript which upon a change to the first dropdown select, the second dropdown is cleared of data, and then an AJAX call is made to a specific URL to update the tags for the productsubgroups dropdown using a partial (_productsubgroup.html.erb).
To do this, the following route set up in routes.rb
get '/update_productsubgroups' => 'products#update_productsubgroups'
so that i can map to the appropriate controller and action. This is all quite fine. I can see the AJAX request in the development.log as where it is querying the database for productgroup #2 (ignore the trailing "&_1422575676984"):
Started GET "/products/update_productsubgroups?productgroup_id=2&_=1422575676984"
The problem, occurs when I use the same content from new.html.erb within the context of editing a product in edit.html.erb. Based on the fact that the routes.rb uses the "resouces :products" directive, I end up with a url for editing products in the form /product/:id/edit (e.g. /product/2/edit to edit the product with ID 2). When I try to use my cascading dropdowns, everytime I make a change to the first selection, I don't get a change in the second dropdown. I can see the request going to the development.log file as:
Started GET "/products/1/update_productsubgroups?productgroup_id=2&_=1422578544393"
and the error that comes up immediately after the request is:
ActionController::RoutingError (No route matches [GET] "/products/1/update_productsubgroups"):
Q1 - Why does the partial just tack on to the existing URL rather than simply make a pure request to /products/update_productsubgroups as is the case when I create a product from the product controller's 'new' action?
Q2 - Is there any way for me to create a rule in the routes.rb to map things correctly?
Q3 - When I try to create a new route as
get '/products/:id/update_productsubgroups', as 'products#update_productsubgroups'
I get an error in the webserver log as:
ArgumentError ('products/:id' is not a supported controller name
I have dug around and I am not certain how to interpret this. Can anyone help explain this so that the last couple of hours can prove a useful learning experience? Unfortunately, most pages either discuss routing for Rails 3 or just refer to the 'Routing from the outside in' page and that seems to confuse me even more because I'm specifying things as expected, namely :controller/:id/:action.
DOH!
I had a relative path specified for my AJAX call! I looked everywhere except the coffeescript file.
$.ajax 'update_productsubgroups',
should be
$.ajax '/update_productsubgroups',
Related
My question: When using AJAX within Rails, from a best practice standpoint, does the HTML verb that I use (e.g., get) to define a route matter? Is it OK to basically always use get?
Context: In my Rails App, I've built the following:
When a user selects an HTML checkbox, that triggers a JQuery listener that lives in a file inside of /app/assets/javascripts.
This .js file makes an AJAX call to a controller/action: foos#bar. My JS passes an ID into the action.
To route this request, I've added the following to routes.rb: get "/foos/bar" => "foos#bar". This tells my App which controller/action should process the AJAX call.
The controller/action handles this request just fine. The action grabs the ID as a URL parameter, updates the relevant model object, and finally returns back a 200 to the JS AJAX caller.
This all works great! No issues -- nothing to troubleshoot here.
My question is: In the example above, is it appropriate to define a get route within routes.rb to process this AJAX request? Or, is that bad practice? Should I instead be defining a put, since conceptually that is what I'm doing in this workflow (i.e., I'm updating an existing object)? I'm worried that, while this all works perfectly, I'm breaking some fundamental MVC routing standards.
If you are updating a resource it will most likely be a PATCH update, which means you aren't completely replacing the resource but are just updating it (this is why PATCH is the default HTTP method for updates in Rails, instead of PUT).
So, yes, you are violating RESTful conventions by using GET to update a resource. GET is only used to fetch a representation of a resource...without changing it in any way.
I have 2 questions:
I have a controller called homepage. I have a view called samplegraph in my homepage's view directory. I want to get the routing working correctly such that www.homepage.com/samplegraph takes me to the samplegraph page.
As far as I can tell, the route for it in routes.rb should be something like this:
GET 'homepage/samplegraph' => 'homepage#showgraph1'
If I'm understanding rails routing correctly, this statement routes GET requests to homepage/samplegraph to the homepage controller's showgraph1 action. At this point I'm not particularly sure what the showgraph1 action should be in order to render the view page(samplegraph). At the moment the action is simply empty. I don't really know what to put here.
Second question:
Also, while I was researching rails routing, I was looking into resource based routing. For my purposes, I don't need most of the stuff generated by that. One thing I am interested in is that invoking resource based routing automatically generates Paths for you via helpers(I think?).
How would I generate a Path for my route, such that I'd be able to use a link_to method to link various parts of the application together? Any help/comments would be greatly appreciated.
Firstly, if you want to get 'samplegraph' page rendered by hitting 'www.homepage.com/samplegraph', you will need to update your route.
Replace
get 'homepage/samplegraph' => 'homepage#showgraph1'
with
get '/samplegraph' => 'homepage#showgraph1'
Now in showgraph1 action of your homepage controller, you will need to render samplegraph view page at last line of the action.
render 'samplegraph'
As of you second question, just hit rake routes on your terminal from your app directory. It will show all routes with helpers which you can use with link_to. You will need to append _path to those routes while using with link_to
Like #RAJ said first of all you need to change your route to
get '/samplegraph' => 'homepage#showgraph1'
At this point I'm not particularly sure what the showgraph1 action should be in order to render the view page(samplegraph)
Rails doesn't care if your action is empty or not, it'll still render your actions view even if it's empty. Since your action is named showgraph1 so it'll make rails look for showgraph1.html.erb with path views/homepage/showgraph1.html.erb
To change this behavior you need to use render 'samplegraph' in your action
One thing I am interested in is that invoking resource based routing automatically generates Paths for you via helpers(I think?)
Rails generate path and url helpers for each route and it doesn't depend on how your routes are defined but you can customize your helper methods by specifying as: option
get 'homepage/samplegraph' => 'homepage#showgraph1', as: 'showgraph'
This will make your helper methods showgraph_path and showgraph_url
I've read the rails guides but there are some things that when I actually do it myself I still do not understand.
For example, how come when I visit my show view on localhost I get an error? Scaffolding created a show action in my controller that is empty and a view but still get an error message.
Similar thing happens with index.
Isn't the purpose of scaffolding to help you with all this? I assumed if I made a few posts that the index action would take me to an index of all the posts but it doesn't instead the post/ itself lists them all. What is the logic behind scaffolding doing this?
EDIT::::
This is the error message that I get:
ActiveRecord::RecordNotFound in ExperimentsController#show
Couldn't find Experiment with id=index
This happens when I visit http://localhost:3000/experiments/index
You are accessing the routes incorrectly.
To visit the index page : you need url http://localhost:3000/experiments
When you specify url : http://localhost:3000/experiments/index, Rails would match it to the route of show page(as shown below): /experiments/:id
If you read the error carefully:
ActiveRecord::RecordNotFound in ExperimentsController#show
Couldn't find Experiment with id=index
Rails mapped the url to show action and is trying to find an experiment with id=index which obviously does not exist and you get an error.
Run rake routes on command prompt and you'll see the routes created for resource experiment as follows:
/experiments index display a list of all experiments
GET /experiments/new new return an HTML form for creating a new experiment
POST /experiments create create a new experiment
GET /experiments/:id show display a specific experiment
GET /experiments/:id/edit edit returns an HTML form for editing an experiments
PATCH/PUT /experiments/:id update update a specific experiment
DELETE /experiments/:id destroy delete a specific experiment
You can access the specific routes with the paths shown above.
Replace :id with an existing experiment records id attribute value.
For eg:
To view an experiment with id 5
Visit http://localhost:3000/experiments/5
NOTE: I would highly recommend you to go through the Rails Routing Guide and get a better idea of how Routing works.
For a simple scaffolding task and assuming you followed the convention of naming, you should never get any errors, but even if you got an error my guess it will be a simple typo or pending-migrations type of error (something a quick googling should resolve)
Scaffolds are meant to give a push and increase Rapid Prototyping of your app but won't do the hole job for you.
I remember being confused just like you some time ago and i too was looking at the wrong direction trying to figure out what Scaffolding do while i should have looked on How Rails template system works which is the next step after learning Rails MVC basics.
Start from the guides, http://guides.rubyonrails.org/layouts_and_rendering.html#overview-how-the-pieces-fit-together and it will take some time to fully understand how rails works!
I'm planning to port our current cms (written in PHP) to Rails. All parts do well, except for one: routing.
Like most cms systems, the routing in our cms based on a database with pages, which are linked to modules, controllers and actions. On this approach a user can fully customize or specify it's own urls.
I know that Rails (and most (application) frameworks have the approach of defining routes in a file, but I hope this is possible.
The approach our users should have is:
add new page
select type (news, form, product, ...)
select an item (select which form, blog or product should be displayed)
enter a url for that page
Special the last point (4) is important. A user should be able to add form A to /contact-us, and form B to /clients/register-as-new-client e.g.
On a request the router needs to do a database query with the page url, to find out which controller, task and parameters should be dispatched.
Question has been updated, and i don't think this is a valid answer anymore
we have a similar paging system. we use a routing glob. in routes.rb:
get 'pages/*lookup_path', to: 'pages#show', defaults: { format: 'html' }, as: 'page'
Just parse params[:lookup_path] in PagesController to suit your needs
'http://localhost/pages/users/'
params[:lookup_path] #=> users/
'http://localhost/pages/users/23'
params[:lookup_path] #=> users/23
'http://localhost/pages/people/1'
params[:lookup_path] #=> people/1
Although this solution isn't ReSTful, I think this should solve the issue.
Regardless, Rails uses routes in a file. You cannot change this since the framework heralds "convention over configiuration". All I can do is point you in a direction to minimize this.
There is a catchall route in Rails (on RailsCasts, and on StackOverflow) which you can use to direct all routing to one controller action. You may further customize the routing behaviour in that method
You could also make a route like…
:controller/:action => Controller::Action
…as is done in CodeIgniter, but now your methods have to have names like contact-us and register-as-a-new-client.
Im trying to get my head around the sequence of events that happen between when rails receives a get/post command and the page is served. I was just trying to map out the sequence myself and i realised i dont fully understand myself which scripts is even ran first so I'd like to clear it up in my head.
many thanks
jon
The request goes into the route matcher which parses the URL, parses the config/routes.rb and if the URL matches a route, it looks for a controller file whose name matches the controller part of the URL, (e.g. http://localhost/categories will look for a CategoriesController)
Then, one of two things happen:
If you're using a Rails restful route, the route matcher applies heuristics to figure out which of the 7 actions to call: a GET on a plural last part is mapped to index; a GET mapped to an ID-looking part after the plural is mapped to show (e.g. categories/1 or categories/something or categories/1-something); a POST to a plural last part is mapped to create; a PUT to an ID-looking part after the plural is mapped to update; a DELETE to the same URL is mapped to destroy; new and edit are mapped to GETs for categories/new & categories/edit.
If you have a custom action, you must have a method in your controller object of the same name.
The chosen action is executed and then Rails either renders the template/file/action specified in the render call within the action or it looks for a view file of the same name as the action and that ends with .html.erb (by default) in the app/views/ directory.
Simple.
Rails does quite a lot of things, a good way to get a decent overview is to read the "Action Controller Overview" document at rails guides: http://guides.rubyonrails.org/action_controller_overview.html
The basic structure is:
rack middleware
routing
filters
controller code
rendering
filters
But rails also does many things by itself to the request. It automatically determines what kind of response you want based on your accept headers, and/or if you manually specify which type of response you want with a file ending like /blog/1.xml. Rails also magically creates a nicely formatted params hash, parsing params like user[name]=foo to {:user => {:name => "foo"}}. Rails also has built-in exception handling and some nice stuff to prevent cross site request forgery and much more, so check out the Controller Overview for the lowdown on that.