Configure routes with post method in rails - ruby-on-rails-3

I am creating a web service in rails application and I need to configure routes with respect to "books/CreateBookItem" with post method.
But since I will not have a view page for this to create a book item, for testing purpose I am typing the url in the browser as
localhost:3000/books/CreateBookItem
But now when I type the above url in browser it is taking as GET request.
So how do I configure the routes for the above.

Add this createbookitem action to books resources in routes.rb:
resources books
collection do
post :createbookitem
end
end
Don't want to have any view for this action then create createbookitem action with disabled render.
class BooksController < ApplicationController
def createbookitem
#do your stuffs
render nothing: true
end
end

Related

Rails redirect_to shows incorrect URL in browser

I have 2 controllers: Games and Players.
Games creates my game and the first player, and redirects to players 'edit' action.
User submits updates to the player, and the Players controller redirects back to games 'show' action.
The user flow works well (the player is updated and the user is shown the game show page), except the URL in the browser upon the final submit still shows 'www.server.com/players/:id'. If I hit refresh on the browser, it will go to the player's show action (as the URL suggests), instead of refreshing the games/show content that is currently on the screen.
What is the preferred approach for fixing this behavior?
Games Controller:
def create
#game = Game.new(params[:game])
if #game.save
redirect_to edit_player_path (#game.players.first)
else
render 'new'
end
end
Players Controller:
def update
#game = current_game
#player = #game.players.find(params[:id])
if #player.update_attributes(params[:player])
redirect_to #game
else
render 'edit'
end
end
ANSWERS to follow up Questions:
current_game is a helper method to retrieve a game (same design as Rails Tutorial http://ruby.railstutorial.org/chapters/sign-in-sign-out )
def current_game
#current_game ||= Game.find_by_remember_token(cookies[:remember_token])
end
routes.rb:
root to: 'static_pages#home'
get "static_pages/home"
resources :games
resources :players
resources :sessions, only: [:new, :create, :destroy]
UPDATE:
I think I have narrowed down the problem. It has to do with jquery_mobile_rails.
I was able to reproduce the behavior by creating a new project with 2 scaffolds and set up routing in the controllers as above. The URL is updated properly without JQM. When I added jquery_mobile_rails gem, and performed a POST, the URL no longer updates.
There is further discussion on the web about this (see links below), but so far I was not able to find a solution:
Rails jquery mobile Routing/Rendering Issue
http://forum.jquery.com/topic/restful-resources-rails-3-and-jquery-mobile

Rails 3.2 Mountable App locale getting duplicated

I am seeing a scenario where my locale parameter is getting duplicated once I step into a mountable app. My app looks like so:
#routes.rb
resources :blogs
scope "(:locale)" do
mount Auth::Engine => '/auth'
end
If I am at a blogs page and look at an auth link it looks like this /en-us/auth/signout which works well, but as soon as I load into any page rendered by the mountable app, for example the profile page /en-us/auth/myprofile', the sign out link now looks like /en-us/auth/signout?locale=en-us
I don't want the querystring getting cluttered, what is causing the app to correctly set the locale parameter and then duplicate it in the querystring?
my bet is that your application controller has something like:
def set_locale
# code here
end
def default_url_options
# code here
end
Since your engine controller inherits from application controller, set_locale may be triggered twice.
Potential Solution: Check if the code is in an engine, then don't trigger locale setting.
This can be done with: self.controller_path().split("/").first == engine_name
I had the same problem. I was setting the default url options on the controller (by redefining default_url_options or by using self.default_url_options=).
The solution was to use Rails.application.routes.default_url_options = instead.

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

Render a page as a saved HTML file using Rails 3.0?

I'm building a simple website generator application in Rails 3.0. I'd like a "publish" action in a controller that works just like an ordinary "show" action, but instead, saves a page as an HTML file in the "public" directory instead of displaying it in the browser. That is, I'd like to use the Rails render mechanism to create a file instead of providing an HTTP response.
What's the best way to do this?
Should I simply add caches_page :publish to the controller?
Or use render_to_string and File.new?
You can use render_to_string method: http://apidock.com/rails/AbstractController/Rendering/render_to_string
You still need to respond from the controller though. Maybe redirect to the page you just saved?
I would go with page caching.
Then if you have editable content, the pages should be automatically generated. You could then write a system task which bundles them up as a web site.
see (whatever)/actionpack/lib/action_controller/caching/pages.rb for instructions.
I found that page caching using caches_page won't work for me because there is no way to show a notification or redirect to another page after caching the page. The method render_to_string (suggested by #Grocery) is the way to go. Here's the example controller code:
def publish
#article = Article.find(params[:id])
html = render_to_string(:template => "articles/template.html.haml", :layout => 'article' )
FileUtils.makedirs("#{Rails.root}/public/articles/") unless File.exists?("#{Rails.root}/public/articles/")
File.open("#{Rails.root}/public/articles/#{#article.filename}.html", 'w') {|f| f.write(html) }
respond_to do |format|
format.html # publish.html.erb
end
end

Rails app doesn't see my views

I've on a while on rails now and here's the problem I've been having on and on:
When I create a controller through:
"rails generate controller ControllerName ViewName"
I get everything working as I want but if for some reason I create the controller through:
"rails generate controller ControllerName"
and then just add ViewName.html.erb to the folder inside views that has the same name as my controller things would go wrong.
So the concrete case is me writing:
rails generate controller Subjects list show.
Which creates for me:
1.controllers>subjects_controller.rb
2.views>subjects>list.html.erb
3.views>subjects>show.html.erb
So this whole thing works fine.But as I already said if I need another view; let's say "new" I just add "new.html.erb" next to the other *.html.erb files and an action:
def new
end
to my subjects_controller.rb then it won't work.
The two previous views would keep working but any other "*html.erb" created outside the command line wouldn't.
Is there anywhere else where info about views is being stored?.
I'm a Windows 7 user (32 bit).Rails version=3.0.3. WebServer=WEBrick.
Text editor = E-TextEditor
This is most likely caused by your routes not being correctly configured. So it would be helpful to see the content of your routes.rb
In your case I think the best way to configure the routes is to use the resources mapping:
resources :subjects
This will by default create routing for the standard RESTful actions :index, :show, :edit, :update, :new, :create and :destroy.
For more detailed information about the routing, I would recommend Rails Routing from the Outside In