Resource helpers in rails console - ruby-on-rails-3

As given on http://guides.rubyonrails.org/routing.html, creating a resourceful route will also expose a number of helpers to the controllers in the application. For example a resourceful route resources :photos will provide helpers like photos_path,new_photo_path etc.
Now, i can call a helper in the rails console using the helper object, for example helper.link_to "this", "that". But calling helper.photos_path in the rails console does not work,however in the controller those helpers are accessible. Why is this so ?
Thank You

route helpers are available within the app object, so you can get access to them this way
app.photos_path # => "/photos"

Related

Removing url scope segment with url helpers

I'm writing an app that makes use of AngularJS, so the app is setup to route all requests to the main home page where angular takes over. All routes are then defined within an api scope which angular uses to retrieve the data. It's setup though, that if the user navigates to a page with a normal URL, then when it redirects to the home page, it maintains that URL which angular then uses to load the correct state.
What I now want to do, is be able to use URL helpers within rails to generate my URL's, but not have the generated URL's include the /api of the scope. Is there any way I can get around this?
routes.rb looks a bit like
scope "/api", shallow_path: "/api" do
... normal stuff here ...
end
And if I try using one of the helpers,
meeting_url(#meeting, subdomain: "test")
the url it generates is
http://test.domain.com/api/meetings/1
Is there a way I can have it strip the /api?
I don't believe there's a built-in way to do it.
But, you're in ruby, so there are plenty of ways to do what you want.
One way to go, since you're in your own app, is do monkey-patch String:
class String
def no_api
self.gsub(/\/api/, '')
end
end
meeting_url(#meeting, subdomain: 'test').no_api #=> http://test.domain.com/meetings/1
If you find that distasteful, you can define a method on ApplicationController or in a helper module:
def no_api(url)
url.gsub(/\/api/, '')
end
etc. etc. etc.

Using a route helper for a controller without a model in rails

I have a controller JaxDataController for responding to ajax requests which has no associated model.
It has a single routes.rb entry match "/jaxdata/:shape_set_id" => "jax_data#fetch"
I'd like to include the path to this model within a .js.coffee.erb view elsewhere in my app. Are there any routing helpers available for this? Failing that, where should i declare a routing helper to be used in any view?
If you specify the :as option in your route, it will create helpers for that route. Thus:
match "/jaxdata/:shape_set_id" => "jax_data#fetch", :as => :jaxdata
You should then be able to refer to jaxdata_path in your views.
See section 3.6 of this guide: http://guides.rubyonrails.org/routing.html

Engine routes in Application Controller

I have a before_filter hook in my main app's application controller that does something like: (It doesn't just put a link in the flash, there is a message, but it isn't relevant to the question, it just accesses the route in the method)
class ApplicationController < ActionController::Base
before_filter :set_link
def set_link
flash[:notice] = items_path
end
end
This works fine for the app, however when I go into the controllers for an engine I made I get the exception
No route matches {:controller=>"items", :action=>"index"}
I understand that when in the engine, the routes helpers are for the engine unless prefixed with main_app
So changing the method in the application controller to
def set_link
flash[:notice] = main_app.items_path
end
Gets rid of the exception but I really don't want to have to do that. Is there another solution to getting the engine to recognize the main_app routes?
EDIT:
This also happens if the application layout calls path helpers. So if the engine is designed to integrated into the main_app's layout then this issue will crop there up too.
Mountable engines are designed to work like this, that is isolate the main app routes and the engine routes.
If you want the two sets of routes to be merged, you can use a non-isolated engine. The first step is removing the isolated_namespace method call in your engine definition:
module MyEngine
class Engine < Rails::Engine
isolate_namespace MyEngine # remove this line
end
end
The second step is to convert your routes in my_engine/config/routes.rb, you should go from this:
MyEngine::Engine.routes.draw do
# stuff that routes things
end
to this:
Rails.application.routes.draw do
# stuff that routes things
end
and remove the mount method call in your application's routes:
App::Application.routes.draw do
mount MyEngine::Engine => "/engine" # remove this line
end
The main advantages of doing it this way would be:
No need to monkey-patch rails. I know devise does this, but this could be a leftover from the days when engines didn't exist in rails.
No need to mount the engine in the application routes. On the other hand, this could backfire if you'd like to control more precisely the insertion point as all you engine routes would be called after (or before, I don't have the answer to this question) your main routes.
If you're looking for documentation on engines, the rails docs for the Engine class are a pretty good starting point. I'd strongly recommend that you read them (in case you haven't yet) if you're interested in the subject.
I figured out how to do this. The problems lies within the isolated namespace. In order to integrate the engine with the app and share the same layout (which may have path helpers from the main app) I did this:
Firstly I removed config/routes.rb from the engine
Then I removed the isolate_namespace from the engine class
module MyEngine
class Engine < Rails::Engine
- isolate_namespace MyEngine
end
end
end
I added a file that was loaded in the engine:
module ActionDispatch::Routing
class Mapper
def mount_my_engine_at(mount_location)
scope mount_location do
#Declare all your routes here
end
end
end
end
Finally, in the main app's config/routes.rb instead of 'mount'ing the engine, you can call your method
mount_my_engine_at "mount_location"
This will basically 'mount' your engine as part of the main app instead of being isolated from it. It is similar to how Devise does it too.
You can keep the isolate_namespace.
In your engine routes.rb
MyEngine::Engine.routes.draw do
...
root to: "something#index"
end
Rails.application.routes.draw do
get "something", to: "my_engine/something#index"
end
And then in the main app routes.rb
Rails.application.routes.draw do
mount MyEngine::Engine => "/anything_you_want"
root to: "main#index"
end
This way you can choose what routes you want to expose (and which you do not)
You can keep the isolate_namespace, as strongly recommended by Rails Engine guide, and do this:
# inside your main_app's config/routes.rb
Rails.application.routes.draw do
root to: 'home#index'
mount MyEngine::Engine, at: "/"
end
# inside your engine's controller
module MyEngine
class SomeController << ::ApplicationController
# include main_app's route helpers
helper Rails.application.routes.url_helpers
end
end
And inside your gem, make sure all the url helpers are prefixed with the correct routing proxy method (e.g. my_engine.pages_path).
Your main_app's layout and engine's controller will route and link to those url helpers correctly to the main app. You don't have to add "main_app" prefix anywhere to the main app. The only downside is you're mounting your engine's routes at main_app's root path, which could collide with any routes by the same name. This is expected anyway if you were to do non-isolate_namespace.
The easiest way is to draw the routes in both the main app, and the engine, so that they are accessible to both:
[MyEngine::Engine, App::Application].each do |app|
app.routes.draw do
# Declare all your routes here
end
end

Rails 3 - index action not loading by default on controller

Now i have a fresh rails 3 install running over rvm 1.9.2
I generated a controller using the follow instruction:
rails generate controller blog index
The output is
create app/controllers/blog_controller.rb
route get "blog/index"
invoke erb
create app/views/blog
create app/views/blog/index.html.erb
invoke test_unit
create test/functional/blog_controller_test.rb
invoke helper
create app/helpers/blog_helper.rb
invoke test_unit
create test/unit/helpers/blog_helper_test.rb
but in browser when i try to get to http://localhost:3000/blog i get:
No route matches "/blog"
but if i type http://localhost:3000/blog/index
it renders the index view.
doesn't it works like Rails 2? where i get to the index view by default with just putting the controller name on the url ?
thanks.
If you look into routes.rb you'll see
get "/blog/index" => "blog#index"
So just remove it with
get "/blog" => "blog#index"
or you can use resources here.
But only question: why do you use singular form? It is nonsensical to call index to singular noun. You should use or "blog#show" as a resource or "blogs#index" as a resources.
Conventions in Rails is a kind of basement. Don't break them if you can follow them
For rails 3:
match '/blog', :controller => 'blog', :action => 'index'
Rails generate does not generate resources for your controller by default. You specified one action for your controller, 'index', so in your case you end up with this in config/routes.rb:
Blog::Application.routes.draw do
get "blog/index"
The simplest thing to do would be to change this to:
get "blog", :to => 'blog#index'
ian.
This is a guess, based on my experience with Rails 2, but here's what I think is happening:
If you'd generated your controller with the scaffold option (that's still in Rails 3, right?), it would have created a model in addition to your controller, and added the corresponding routes via a call to map.resources (or Rails 3 equivalent) - this last bit is what gives you the /models routes you're expecting.
But since you just generated the controller, no model was created, and thus Rails doesn't put in a map.resources statement in routes.rb - map.resources really only makes sense when there's a model underlying your controller. In fact, I don't think it adds any special routes when you generate a controller; you're getting to your index by one of the default routes: /:controller/:action.
So if you want to get to your index from /blog, you'll have to add the route yourself. Luckily, it should be a one-liner.
Hope this helps!
PS: And if you're paranoid, you'll want to disable those default routes before you go to production - they allow GET requests to trigger actions that change your database (e.g. GET:/blog/destroy), opening you up to Cross-Site Request Forgery attacks.
Add this to your routes.rb file match ':controller(/:action(/:id))(.:format)'
It's better if you add it at the bottom of the routes.rb file.
The problem with this approach is that it will make all your actions available through get request. So be careful with that.
Instead of manual routing you can go to /app/controllers/application_controller.rb and add a blank index method
def index
end
make sure your generated controller extends the application controller, and boom all your generated controllers do what you want
Tested on Rails 3.2.*

Rspec2 and Rails 3 - View Spec Routing for Nested Resources

I have a nested resource, setup like this:
resources :chickens do
resources :eggs
end
The views for the EggsController are under views/eggs, but:
describe "eggs/index.html.erb" do
gives a "No route matches {:action => "create", :controller => "eggs"} error on calling render. How do I get RSpec to find the correct (nested) route for view specs?
As a side note, is there any way to specify a nested resource to the Rails 3 controller scaffold generator?
The test looks ok to me...
By any chance do you have a form on your eggs/index.html.erb for creating new eggs that might not yet be wired up correctly? It seems it may be trying to render the index view but failing because the view is trying build a route that doesn't exist? You'd want to make sure that the form is using the correct nested resource route. Does the view render when you load it up in the browser?