I had this route in my Rails 2.x app
map.with_options(:controller => "web_page") do |site|
site.connect "*url", :action => "index"
end
which directed every namespace after my root to a controller called 'web_page' and to an action called 'index'
For example, if a I type http://localhost:3000/products it goes to http://localhost:3000/web_pages/index
If I type http://localhost:3000/services still it goes to http://localhost:3000/web_pages/index
But how can I do this in Rails 3 routes?
You can use:
match '/:all' => 'web_page#index', :constraints => { :all => /.+/ }
request to http://example.com/this/is/a/test?option=true become:
class WebPageController < ApplicationController
def index
#all = params[:all] # "this/is/a/test"
#path = request.path # "/this/is/a/test"
#query = request.query_parameters # {"option"=>"true"}
end
end
Related
I'm upgrading rails 2.3.2 app ot rails 3.
Have unknown error with sending email message in MailerFormError.
MailerFormError is my model: class MailerFormError < ActionMailer::Base
At 1st I have error with 'deliver_send' method (undefined method `deliver_sent' for MailerFormError:Class),
I change it to 'send'. Now I have this:
NoMethodError in LeadsController#create
undefined method `part' for #
My code in controller:
#msg = {}
#msg["errors"] = #lead.errors
#msg["params"] = params
#MailerFormError.deliver_sent(#msg)
MailerFormError.sent(#msg)
This is my class with sending method:
def sent(msg, sent_at = Time.now)
#subject = ("Ошибка при заполнении формы").force_encoding('iso-8859-1').encode('utf-8')
#recipients = 'mymail#gmail.com'
#from = 'mymail#gmail.com'
#sent_on = sent_at
#headers = {}
part( :content_type => "multipart/alternative" ) do |p|
p.part :content_type => "text/plain",
:body => render_message("sent.plain.erb", :msg=>msg )
end
end
1) for Rails 3, to send your notification in your controller , you have to write this :
MailerFormError.sent(#msg).deliver
2) And you have to rewrite your 'sent' method in the Rails 3 way :
def sent(msg, sent_at = Time.now)
...
mail(:to => '...', :from => '...', :subject => '...') do |format|
format.html
format.text
end
...
end
You can also create the text version and html in your view directory app/views/mail_form_error : sent.text.erb and sent.html.erb
i want to rebuild an app which is a typical rails 3.2 mvc app into a API + Frontend (Backbone) only. As I have no experience in building APIs in rails including authenticatin:
What's the best way to authenticate with devise using backbone? Using auth_tokens?
How should I make he API? Just printing out JSON or use a gem like Grape?
thanks in advance!
I can explain you the way i do this :
First, i install a standard rails application with devise. After that, i create my own session controller :
class SessionsController < ApplicationController
def authenticate
# this method logs you in and returns you a single_access_token token for authentication.
#user = User.find_for_authentication(:email => params[:user][:email])
if #user && #user.valid_password?(params[:user][:password])
render :json => {:user => {:email => #user.email, :id => #user.id, :firsname => #user.firstname, :lastname => #user.lastname, :team_id => #user.team_id, :singleAccessToken => #user.generate_access_token}}
else
render :json => {:errors => ["Nom d'utilisateur ou mot de passe invalide"]}, :status => 401
end
end
end
As you can see, i send a request to this url with the json looking like :
{
user => {
email => "myemail#toto.com",
password => "monpass"
}
}
And my controller return me the json with user data if every thing is fine, or an error. On json with user, i return an access_token used on next requests to check that the user is allowed to request. I made this filters in my application controller :
class ApplicationController < ActionController::Base
protect_from_forgery
protected
def user_access_token
request.headers["HTTP_X_USER_ACCESS_TOKEN"] || request.headers["HTTP_USER_ACCESS_TOKEN"]
end
def current_user
if token = user_access_token
#user ||= User.find_by_access_token(token)
end
end
def require_user
unless current_user
render :json => {:error => "Invalid Access Token"}, :status => 401
end
end
def require_owner
unless current_user && current_user == object.user
render :json => {:error => "Unauthorized"}
end
end
end
As you can see, on each next request, i will add the access_token in html header on key : HTTP_USER_ACCESS_TOKEN
So, i can check if the user is allowed to make the request.
To make an API, you can use the Rails API gem as see here :
http://railscasts.com/episodes/348-the-rails-api-gem
Good luck.
I use Devise and I want to do my logout action.
What I want to do is, that when I log out, I want to create a own JSON object to return. At this time, after I logt out, I get all my root articles.
How can I write my own destory action like I have found the create action?
class SessionsController < Devise::SessionsController
def create
resource = warden.authenticate!(:scope => resource_name, :recall => :failure)
return sign_in_and_redirect(resource_name, resource)
end
def sign_in_and_redirect(resource_or_scope, resource=nil)
scope = Devise::Mapping.find_scope!(resource_or_scope)
resource ||= resource_or_scope
sign_in(scope, resource) unless warden.user(scope) == resource
return render :json => {:success => true, :redirect => stored_location_for(scope) || after_sign_in_path_for(resource)}
end
def failure
return render:json => {:success => false, :errors => ["Login failed."]}
end
end
And my Routes in routes.rb
devise_for :users, :controllers => {:session => "sessions"} do
get "/users/sing_out" => "devise/sessions#destroy"
end
this is the destroy method of the sessions-controller.
you should be able to customize it to your needs. i think that it would be wiser to add another action and implementing your custom behavior there, as this will be less likely to cause unexpected errors with upgrading devise in the future.
# DELETE /resource/sign_out
def destroy
redirect_path = after_sign_out_path_for(resource_name)
signed_out = (Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name))
set_flash_message :notice, :signed_out if signed_out
# We actually need to hardcode this as Rails default responder doesn't
# support returning empty response on GET request
respond_to do |format|
format.any(*navigational_formats) { redirect_to redirect_path }
format.all do
method = "to_#{request_format}"
text = {}.respond_to?(method) ? {}.send(method) : ""
render :text => text, :status => :ok
end
end
end
Is there a better way to write such routs in rails 3 ?
I converted my application from rails 2 to rails 3 .
match "/resume/education/edit_education",
:controller => "resume/education#edit_education",
:as=>"resume_edit_education"
match "/resume/education/update_education",
:controller => "resume/education#update_education",
:as=>"resume_update_education"
match "/resume/education/cancel_education_add",
:controller => "resume/education#cancel_education_add",
:as=>"resume_cancel_education_add"
match "/resume/education/cancel_education_edit",
:controller => "resume/education#cancel_education_edit",
:as=>"resume_cancel_education_edit"
match "/resume/education/remove_education",
:controller => "resume/education#remove_education",
:as=>"resume_remove_education"
match "/resume/education/update_education_title",
:controller => "resume/education#update_education_title",
:as=>"resume_update_education_title"
match "/resume/education/move_up",
:controller => "resume/education#move_up",
:as=>"resume_education_move_up"
match "/resume/education/move_down",
:controller => "resume/education#move_down",
:as=>"resume_education_move_down"
match "/resume/education/remove",
:controller => "resume/education#remove",
:as=>"resume_remove_education"
I think you should refactor your controller like this
class Resume::EducationController
def cancel_add
end
def cancel_edit
end
def update_title
end
def move_up
end
def move_down
end
def update
end
def destroy
end
end
Then you could organize your routes thus
namespace :resume do
resource :education, :only => [:update, :destroy] do
collection do
get 'cancel_add'
get 'cancel_update'
get 'update_title'
get 'move_up' # get -> put ?
get 'move_down'
end
end
end
Look to guide Rails Routing from the Outside In
I have a custom redirection in my routes.rb which works fine at the ui:
match ':hash' => redirect { |params| begin url = Sharing.find_by_short_url(params[:hash]); "/#{url.shareable_type}/#{url.shareable_id}/" rescue '/' end }, :constraints => { :hash => /[a-zA-Z0-9]{7}/ }
What is does is takes a shortened url and looks up the actual url path.
However my test is failing:
it "routes GET 'STU1VWX' to stations/1" do
{ :get => "STU1VWX" }.should redirect_to(
:controller => "stations",
:action => "show",
:params => {:id => 1}
)
end
With:
1) Shorter URL redirect routes GET 'STU1VWX' to stations/1
Failure/Error: { :get => "STU1VWX" }.should route_to(
ActionController::RoutingError:
No route matches "/STU1VWX"
# ./spec/routing_spec.rb:12:in `block (2 levels) in <top (required)>'
So the problem is isolated at the test level. I know I could test this in a controller test but given that the code is in routes.rb I should not have to. Is there inherently a reason that using should route_to not to work in the case of redirection?
Looks like you're saying here that if you can't find the page belonging to the hash, then redirect to "/"
There's something really stinky about performing an ActiveRecord find in your routes.
If you have to redirect to a specific controller depending on the sharable type, then I'd put this as a separate controller with a redirect:
match "/:hash" => 'SharableController#redirect':constraints => { :hash => /[a-zA-Z0-9]{7}/ }
and then deal with finding the record and redirecting to the correct controller action from there:
class SharableController < ApplicationController
def redirect
#sharable = Sharable.find_by_sharable_type(params[:hash])
redirect_to controller: #sharable.sharable_type, action: 'show', id: #sharable.id
end
end
OR... depending on how similar the show actions are:
class SharableController < ApplicationController
def redirect
#sharable = Sharable.find_by_sharable_type(params[:hash])
render template: "#{#sharable.sharable_type.pluralize}/show"
end
end
If you're only dealing with GET requests, better to swap out match for get by the way:
get "/:hash" => 'SharableController#redirect', :constraints => { :hash => /[a-zA-Z0-9]{7}/ }