Rails application route cannot access from Grape API - ruby-on-rails

I'm requesting for any user from a different rails application. I'm using grape gem. The below code is the requested user's information sending controller action.
but unfortunately it is showing error:
NoMethodError (undefined method `profile_url' for #<Grape::Endpoint:0xdadef8c>):
What is the problem? My rake routes showing the url does exists.
module V1
class User < Grape::API
version 'v1', using: :path
format :json
prefix :api
resource :user do
desc "find any user"
params do
requires :email, type: String
requires :password, type: String
end
get :create do
user = User.find_by_email(params[:email])
if user.present?
if user.valid_password?(params[:password])
{user: user, profile_url: profile_url(user.profile)}
else
{:notice => "Invalid password for email: #{params[:email]}"}
end
else
{:notice => "No user found with email: #{params[:email]}"}
end
end
end
end
end
rake routes | grep profile:
profiles GET /profiles(.:format) profiles#index
POST /profiles(.:format) profiles#create
new_profile GET /profiles/new(.:format) profiles#new
edit_profile GET /profiles/:id/edit(.:format) profiles#edit
profile GET /profiles/:id(.:format) profiles#show
PATCH /profiles/:id(.:format) profiles#update
PUT /profiles/:id(.:format) profiles#update
DELETE /profiles/:id(.:format) profiles#destroy

Make sure you mounted the resource properly.
You may need something like this:
mount API::v1::User
See more about mounting here
Also, take a look at this post. Might be helpful to see how you can mount your resource while using Grape gem.

You can do it like this:
Rails.application.routes.url_helpers.profile_url(user.profile)

Related

How to access devise token auth registration controller?

I am using Devise auth token gem for authenticating some parts of my rails app. But when I try to create a new user with the registration path, it is giving me the following error{"errors":["Authorized users only."]}.
Here is the rspec code that I am using for the test,
it 'creates a user using email/password combo' do
post api_user_registration_path, { email: 'xxx', password: 'yyy',password_confirmation: 'yyy'}
puts last_response.body
expect(last_response.body).not_to have_content('error')
end
Additional info: the model name is 'User' and the routes looks like,
namespace :api do
scope :v1 do
mount_devise_token_auth_for 'User', at: 'auth'
end
end
I understand that the devise is expecting the user to be authenticated before accessing this path, but this being the user registration, it needs to be outside the authentication. Can you suggest a solution for this? Is there any configuration that I am missing here?
Try with:
namespace :api do
namespace :v1 do
mount_devise_token_auth_for 'User', at: '/auth'
end
end
This will create the following routes:
new_api_v1_user_session GET /api/v1/auth/sign_in(.:format) devise_token_auth/sessions#new
api_v1_user_session POST /api/v1/auth/sign_in(.:format) devise_token_auth/sessions#create
destroy_api_v1_user_session DELETE /api/v1/auth/sign_out(.:format) devise_token_auth/sessions#destroy
api_v1_user_password POST /api/v1/auth/password(.:format) devise_token_auth/passwords#create
new_api_v1_user_password GET /api/v1/auth/password/new(.:format) devise_token_auth/passwords#new
edit_api_v1_user_password GET /api/v1/auth/password/edit(.:format) devise_token_auth/passwords#edit
PATCH /api/v1/auth/password(.:format) devise_token_auth/passwords#update
PUT /api/v1/auth/password(.:format) devise_token_auth/passwords#update
cancel_api_v1_user_registration GET /api/v1/auth/cancel(.:format) devise_token_auth/registrations#cancel
api_v1_user_registration POST /api/v1/auth(.:format) devise_token_auth/registrations#create
new_api_v1_user_registration GET /api/v1/auth/sign_up(.:format) devise_token_auth/registrations#new
edit_api_v1_user_registration GET /api/v1/auth/edit(.:format) devise_token_auth/registrations#edit
PATCH /api/v1/auth(.:format) devise_token_auth/registrations#update
PUT /api/v1/auth(.:format) devise_token_auth/registrations#update
DELETE /api/v1/auth(.:format) devise_token_auth/registrations#destroy
api_v1_auth_validate_token GET /api/v1/auth/validate_token(.:format) devise_token_auth/token_validations#validate_token
Also create an controller in app/controllers/api/v1/api_base_controller.rb
class Api::V1::BaseApiController < ActionController::Base
include DeviseTokenAuth::Concerns::SetUserByToken
end
Also add to your file app/controllers/application_controller.rb
before_action :configure_permitted_parameters, if: :devise_controller?

Devise hide the user id from the url

When editing a user in devise the edit_user_registration_path route is:
edit_user_registration GET /users/edit(.:format) devise/registrations#edit
I would like to have a route to edit a user's profile without disclosing the user_id in the url however my route is:
edit_profile GET /profiles/:id/edit(.:format) profiles#edit
How can I create a similar route and hide the user_id from the url?
EDIT
Ok, I worked this one out... partially using:
http://guides.rubyonrails.org/routing.html#singular-resources
I have created a singular resource in my routes.rb file
resource :profile
This now allows me to view the current user's profile with /profile and edit the current user's profile with /profile/edit
However when I edit the current user's profile and click update I am redirected to /profile.1? /profile.2 /profile.3 and so on all display the current user's profile.
Where does the profile.X come from and how do I simply redirect back to /profile after I update?
My update action is simply:
def update
#profile.region = set_region(params[:postal_code], params[:country])
#profile.assign_attributes(profile_params)
#profile.save
#profile.user.update_attributes (user_params)
respond_with(#profile)
end
Your question is
Where does the profile.X come from and how do I simply redirect back
to /profile after I update?
Run the following command
$ rake routes | grep profile
profile POST /profile(.:format) profiles#create
new_profile GET /profile/new(.:format) profiles#new
edit_profile GET /profile/edit(.:format) profiles#edit
GET /profile(.:format) profiles#show
PATCH /profile(.:format) profiles#update
PUT /profile(.:format) profiles#update
DELETE /profile(.:format) profiles#destroy
As you can see profile_path receives no parameter. A parameter passed to profile_path will be interpreted as format. You can try the following in Rails console
> app.profile_path
=> "/profile"
> app.profile_path(1)
=> "/profile.1"
> app.profile_path("json")
=> "/profile.json"

no route matches - rails 4.0

I have a route set up as such:
get 'password reset' => 'password_resets#edit', :as => 'password_reset'
resources :password_resets
I have a controller as such:
class PasswordResetsController < ApplicationController
def new
end
def create
user = User.find_by_email(params[:email])
if user
user.send_password_reset
redirect_to root_url, :notice => 'Email has been sent. Please follow instructions to reset your password.'
else
redirect_to password_resets_path
flash[:error] = 'Sorry but we do not know that email.'
end
end
def edit
#user = User.find_by_password_reset_token!(params[:id])
end
end
I then sent an email off and used letter_opener to view its contents in browser:
No route matches {:controller=>"password_resets", :action=>"edit", :format=>"lYoa1Rh6yfwL2olfwkODnQ"} missing required keys: [:id]
I then did rake routes
password_resets GET /password_resets(.:format) password_resets#index
POST /password_resets(.:format) password_resets#create
new_password_reset GET /password_resets/new(.:format) password_resets#new
edit_password_reset GET /password_resets/:id/edit(.:format) password_resets#edit
GET /password_resets/:id(.:format) password_resets#show
PATCH /password_resets/:id(.:format) password_resets#update
PUT /password_resets/:id(.:format) password_resets#update
DELETE /password_resets/:id(.:format) password_resets#destroy
Why am I getting this error? all my mailer tests are passing ... but trying this in browser means that eaither my mailer tests are lying or something is wrong.
If I try doing a link like:
link_to "Some where", edit_password_reset_url(#user.password_reset_token)
The browser works but the tests fail ... with the same error message.
try
link_to "Some where", edit_password_reset_url(id: #user.password_reset_token)
If user.password_reset_token = lYoa1Rh6yfwL2olfwkODnQ
You should send ID of this password table to the edit action.

RSpec routes recognision

I have an interesting situation which leaves me scratching my head.
I've created a controller (without a model) to generate password resets. I've defined a RESTful route to the controller:
routes.rb
resources :password_resets
I've created some action on the controller, in particular my edit action:
password_resets_controller.rb
class PasswordResetsController < ApplicationController
# code omitted
def edit
#user = User.find_by_password_reset_token!(params[:id])
end
# code omitted
end
The user can access the edit from the email that I send to the user:
password_reset.html.haml
%p To reset your password, click the URL below.
= edit_password_reset_url(#user.password_reset_token)
So far so good, I've managed to use the code.
Then I have the spec that tests my mailer:
describe "password reset" do
let(:user) { FactoryGirl.create(:user) }
let(:mail) { UserMailer.password_reset(user) }
it "sends user password reset url" do
mail.to.should eq([user.email])
end
end
Surprisingly, I get the following:
Failure/Error: let(:mail) { UserMailer.password_reset(user) }
ActionView::Template::Error:
No route matches {:action=>"edit", :controller=>"password_resets"}
# ./app/views/user_mailer/password_reset.html.haml:5:in `_app_views_user_mailer_password_reset_html_haml__1760284087840822602_11954840'
# ./app/mailers/user_mailer.rb:7:in `password_reset'
Yet there is a route match, at least by looking at my routes:
password_resets GET /password_resets(.:format) password_resets#index
POST /password_resets(.:format) password_resets#create
new_password_reset GET /password_resets/new(.:format) password_resets#new
edit_password_reset GET /password_resets/:id/edit(.:format) password_resets#edit
password_reset GET /password_resets/:id(.:format) password_resets#show
PUT /password_resets/:id(.:format) password_resets#update
DELETE /password_resets/:id(.:format) password_resets#destroy
What could possible go wrong in my test/routes?
Many thanks.
Check if Factory user has password_reset_token. Most likely it is nil, same routing error you can get for any edit_something_url(nil)

Rails 3.0: error with routes when overriding to_param in model

I'm getting an error with my routes when I try to override to_param in my user model to use the email address as the id. It appears to be trying to match the entire object for the id when it tries to match the route. Can anyone help me figure out what I'm missing?
Here's the error:
No route matches {:controller=>"users", :action=>"show", :id=>#<User id: 1, email: ....>}
Here's how I've set up the code.
models/user.rb:
attr_accessible :email
def to_param
email
end
controllers/users_controller.rb:
before_filter :get_user, :only=>[:show,:update,:edit,:destroy]
...
def get_user
#user = User.find_by_email params[:id]
end
config/routes.rb
resources :users
And here's the output from rake routes:
user GET /users(.:format) {:controller=>"users", :action=>"index"}
POST /users(.:format) {:controller=>"users", :action=>"create"}
new_user GET /users/new(.:format) {:controller=>"users", :action=>"new"}
edit_user GET /users/:id/edit(.:format) {:controller=>"users", :action=>"edit"}
user GET /users/:id(.:format) {:controller=>"users", :action=>"show"}
PUT /users/:id(.:format) {:controller=>"users", :action=>"update"}
DELETE /users/:id(.:format) {:controller=>"users", :action=>"destroy"}
The problem is that the email adds a '.' (dot) in the url, and that confuses rails, because it tries to find a "com" format (if the email ends in .com)
I've added this code to one of my apps (I have People instead of Users) and it works properly, so the trick is to replace the dot with something else. I chose to replace it with an '#' as other symbols such as - or + are valid in email addresses.
file person.rb
def to_param
email.sub ".", "#"
end
def self.param_to_email(param)
segments = param.split '#'
host = segments[1..-1].join('.')
segments[0] + '#' + host
end
file people_controller.rb
def get_person
email = Person.param_to_email params[:id]
#person = Person.find_by_email email
end
There are some more hints about how this works in http://jroller.com/obie/entry/seo_optimization_of_urls_in.
Thanks for the question, I'm just starting with rails, so this is really helping me to understand how it works :).
You can include dots '.' in your to_param return value if you specify a custom regular expression for the 'id' parameter in your route, for example:
match '/images/:id',
:via => :get,
:constraints => { :id => /[^\/]+/ },
:format => false,
:to => 'images#show',
:as => :image
See http://edgeguides.rubyonrails.org/routing.html#specifying-constraints for more details.
I encountered problems with sending email address trough GET.
#this url will cause the following problem
/resend-validation/abcd#abcd.com
params[:email] = abcd#abcd
# I had to encode the email:
<%= link_to('Resend Code', resend_activation_path(:email => user.email.unpack('H*'))) %>
# than decode it in controller:
email = params[:email].split.pack('H*')
To avoid problems passing '.' (dot) through the URL you can add in your routes definition:
resources :users, :id => /.*/
credits to: https://stackoverflow.com/a/8943634/333061

Resources