My MembersController is in app/controllers/api/v1/members_controller:
class API::V1::MembersController < ApplicationController
include DeviseTokenAuth::Concerns::SetUserByToken
***before_action :authenticate_api_v1_member!***
def index
#members = Member.all
render json: #members
end
In my member.rb
class Member < ActiveRecord::Base
# Include default devise modules.
devise :database_authenticatable, :registerable
include DeviseTokenAuth::Concerns::User
end
In my member_serializer:
class MemberSerializer < ActiveModel::Serializer
attributes :email, :uid, :name, :nickname, :admin
end
My question is:
If I don't have the line before_action :authenticate_api_v1_member!, I can send request from Postman to '/api/v1/members' and I can get the JSON respond.error here
Blockquote
If I have the line above, with header include 'uid, client, access-token', I get the error below:
header 'client, access-token', the error is below:
error here
How can I send request to the 'members#index' with devise_token_auth??? Thanks in advance.
I've solved my problem and If anybody face the same issue, contact me by post an comment on this and I'll post answer.
Related
First-time poster, many-time finder-of-answers on the site (thank you!). I'm using Rails 5.2.3, ruby-2.6.2 and Devise gem 4.6.2. I have not been able to get an answer to work, even though there are plenty somewhat related questions here, here, here and here.
When a new User signs up, I want them to select their Company from a dropdown list (already created) in the sign-up form. (Eventually, this will be an admin role, but that's beyond the scope of this question.)
I created a registrations controller and added code per a number of the previous posts. Update, I was not extending Devise as I should have as indicated here: Extending Devise Registration Controller. This is my new Registrations controller.
class Users::RegistrationsController < Devise::RegistrationsController
before_action :configure_sign_up_params, only: [:create]
before_action :configure_account_update_params, only: [:update]
def new
#companies = Company.all
super
end
def create
#companies = Company.all
super
end
protected
def configure_sign_up_params
devise_parameter_sanitizer.permit(:sign_up, keys: [:company_id])
end
def configure_account_update_params
devise_parameter_sanitizer.permit(:account_update, keys: [:company_id])
end
end
And created new files in views/registrations with new.html.erb and edit.html.erb that I copied the exact code from the devise/registrations views.
I updated my routes.rb file to include:
devise_for :users, :controllers => { registrations: 'users/registrations', sessions: 'users/sessions' }
My User model is:
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
belongs_to :company
accepts_nested_attributes_for :company
end
My Company model is:
class Company < ApplicationRecord
has_many :users
end
In the new user registration form, this works to provide the dropdown, but when I try to create the new user, it says: 1 error prohibited this user from being saved: Company must exist.
<%= f.collection_select :company, #companies, :id, :name, prompt: true %>
I thought this post would have the answer, but that appears to use Rails 3 and attr_accessible, which was deprecated in Rails 4.
I don't really understand what accept_nested_attributes_for :company does. The only thing in the Company model is the name.
Thank you in advance!
Welcome to StackOverflow.
In order to add more parameters to devise's sign up form, you'll need to sanitize the corresponding parameters using devise's sanitizer.
You should do that like this:
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:company_id])
end
end
You can find more information about parameter sanitizing and adding custom fields in this section of devise's readme
If you also want to add a select field including all the existing companies, you should add a collection select:
<%= f.collection_select :company_id, Company.all, :id, :name %>
Got it!
To extend the Devise controller, follow the help here: Extending Devise Registration Controller
The User models must also be updated to include the optional: true because here https://blog.bigbinary.com/2016/02/15/rails-5-makes-belong-to-association-required-by-default.html:
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
belongs_to :company, optional: true
accepts_nested_attributes_for :company
end
I have the following method in an API controller:
module Api
module V1
class ArticlesController < Api::BaseController
def show
article = Article.find(params[:id])
render json: article
end
end end end
And while using the active_model_serializers gem, I have the following serializer:
class Api::V1::ArticleSerializer < ActiveModel::Serializer
attributes :id, :author_id, :title, :description
end
For all API requests the server should include information about the session, such as the api token and the current user. So in the above case the generated json shouldn't only include the attributes mentioned in the articles serializer but also for example the api token.
Where and how does one normally include this session information to send to the API front end? Is this perhaps in a separate serializer that is included in addition to in this case the articles serializer?
Since you want this information attached to all API responses, it makes sense to have a superclass serializer responsible for this, which all other serializers inherit from:
class SerializerWithSessionMetadata < ActiveModel::Serializer
attributes :token, :user
def token
# ...
end
def user
# ...
end
end
Then your serializers would inherit from this instead of ActiveModel::Serializer:
class ArticleSerializer < SerializerWithSessionMetadata
# ...
end
Alternatively, you could make it a module that you include in your serializers:
module SessionMetadataSerializer
def self.included(klass)
klass.attributes :token, :user
end
def token
# ...
end
# ...
end
Then:
class Api::V1::ArticleSerializer < ActiveModel::Serializer
include SessionMetadataSerializer
attributes :id, :author_id, :title, :description
end
I am following Ryan Bate's Multitenancy with Scopes tutorial (http://railscasts.com/episodes/388-multitenancy-with-scopes) and I ran into the following error when I attempted to scope my users to the correct tenant:
undefined method users for #<Tenant:0x007fc61f075228>
The error references my show action in my users_controller.rb:
def show
#user = current_tenant.users
end
This occurred because I removed the relationship in Tenants.rb to add cattr_accessor :current_id
class Tenant < ActiveRecord::Base
cattr_accessor :current_id
#has_many :users
def self.current_id=(id)
Thread.current[:tenant_id] = id
end
def self.current_id
Thread.current[:tenant_id]
end
end
In my user.rb, I added the default_scope:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
default_scope { where(tenant_id: Tenant.current_id) }
end
Here is my applications_controller.rb:
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
around_filter :scope_current_tenant
def after_sign_in_path_for(resource_or_scope)
user_show_path(current_user.id)
end
private
def current_tenant
Tenant.find_by_subdomain! request.subdomain
end
helper_method :current_tenant
def scope_current_tenant
Tenant.current_id = current_tenant.id
yield
ensure
Tenant.current_id = nil
end
end
I am not sure why Ryan removed the has_many :users relationship, but I assume it is to prevent users with different tenants to view each other.
How do I handle and fix this error?
It seem like you do not need use
current_tenant.users
It scoped request to db automatic (uses default scope in user model).
Just
#users = Users.all
How do I customize the JSON output on creation of a devise User?
### User.rb ###
class User < ActiveRecord::Base
devise :database_authenticatable,
:registerable, ...
...
end
### Routes.rb ###
...
devise_for :users, :controllers => {:registrations => "registrations"}
...
I've got some extra fields in my User table that are secret, but they get returned in the JSON response when I do a User creation via JSON like this:
$ curl -H "Content-Type: application/json" -d '{"user" : {"username":"someone","email":"someone#somewhere.com","password":"awesomepass"}}' -X POST http://localhost:3000/users.json
which returns:
{"user":{"secret_field_1":"some value","secret_field_2":"some value","created_at":"2013-07-25T21:24:50-05:00","email":"someone#somewhere.com","first_name":null,"id":3226,"last_name":null,"updated_at":"2013-07-25T21:24:50-05:00","username":"someone"}}
I'd like to hide those secret fields, but don't know how to customize the JSON response.
I've tried a standard ActiveRecord serializer:
class UserSerializer < ActiveModel::Serializer
attributes :id, :created_at, :updated_at, :email, :first_name, :last_name, :username
end
to no avail, I'm guessing because of Devise.
I just ran into the same issue. I haven't pinpointed exactly why but it looks like respond_with in Devise's SessionsController (tested on Devise 3.0 and active_model_serializers 0.8.1) doesn't trigger the ActiveModel::Serializer.
So I overrode respond_with in my controller:
class SessionsController < Devise::SessionsController
def respond_with(resource, opts = {})
render json: resource # Triggers the appropriate serializer
end
end
It is, however, working in my RegistrationsController with respond_with. There I needed to do the following:
class RegistrationsController < Devise::RegistrationsController
respond_to :json
end
I recently ran into this and overriding respond_with didn't fix the issue. I ended up overriding to_json in user.rb like so:
def to_json(arg)
UserSerializer.new(self).to_json
end
Not sure what the extra arg is, but that seems to be required by one of the devise mixins.
I'm using the following:
Rails 4.2.0
Devise 3.4.1
Just a guess, but it sounds like rails is not finding your serializer and is using to_json(). Did you define active_model_serializer() in your model?
I just had the same problem, below is how I resolved it, very simple.
All these passed in active_model_serializers (0.9.5)
Override Devise registration method, and in your customize action:
def registration
//Some process, and you get a #user when registration is successful.
render :json => UserSerializer.new(#user)
end
If you want to pass some parameters to your customized Serializer(token for example), you can pass it in your action:
render :json => UserSerializer.new(#user).as_json({auth_token: your_token})
And in your serializer, just use:
class UserSerializer < ActiveModel::Serializer
attributes :id, :name, :avatar_url, :auth_token
def auth_token
serialization_options[:auth_token]
end
end
Depending on what you are doing with that JSON, you simply have to remove attributes you don't want from your serializer.
For example :
class UserSerializer < ActiveModel::Serializer
attributes :id, :email, :username
end
I presume that, in your case, you just want to do that.
But you also have the possibility to include an attribute on a specific condition :
class PostSerializer < ActiveModel::Serializer
attributes :id, :title, :body, :author
def include_author?
current_user.admin?
end
end
And finally you can override the attributes method to return the hash you need :
class PersonSerializer < ActiveModel::Serializer
attributes :first_name, :last_name
def attributes
hash = super
if current_user.admin?
hash["ssn"] = object.ssn
hash["secret"] = object.mothers_maiden_name
end
hash
end
end
See README of ActiveModel::Serializers for more informations.
I recently started to learn ruby on rails and I was able to successfully create an app and add users with devise, also add an avatar to the user with paperclip.
Now I'm having a problem on how to display the avatar throughout the app. The avatar only displays in http:localhost:3000/users/... (within the devise folders) for exemple, but if I try to create a new page, model, controller http://localhost:3000/profile/ for exemple, using the the tag
<%= image_tag #user.avatar.url(:thumb) %>
the page will not load and will return this error
undefined method 'avatar?' for nil:NilClass
It's probably something really simple, but I can't figure out how to fix it.
My model user.rb looks like this:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
validates_uniqueness_of :username
has_attached_file :avatar, :styles => { :medium => "300x300>", :thumb => "100x100>" }
attr_accessible :name, :username, :email, :password, :password_confirmation, :remember_me, :avatar
attr_accessor :current_password
end
And my controller looks like this:
class UserController < ApplicationController
def profile
end
end
Thanks!
On routes.rb, you should have something like this:
match "profile" => "user#profile"
On your UserController, you should have something like this:
class UserController < ApplicationController
def profile
#user = current_user
end
end
And then you'll be able to use #user.avatar.url. Also, pay attention that if you don't have a logged in user, current_user will be nil, and then you will have the error you described, so please add something like this on your controller:
class UserController < ApplicationController
before_filter :authenticate_user!
def profile
#user = current_user
end
end
And then, when a unauthenticated account tries to access /profile, it'll be redirected to the login form.
I am still new to Rails so correct me if I am wrong but I think this might work for you.
class UserController < ApplicationController
def profile
#user = User.find(current_user.username)
end
end