Hi I am trying to include the roles of a user when rendering json doing User.all
I am using ruby on rails and Mongoid
I only get the role_id in my response...
role_id":"56cb596bc226cb5c04efd1cb
User model:
class User
include Mongoid::Document
include ActiveModel::SecurePassword
has_many :role
belongs_to :store
has_many :orders
Role model:
class Role
include Mongoid::Document
belongs_to :user
field :name, type: String
field :active, type: Mongoid::Boolean
the response I get:
{"_id":"...","api_key":"...","email":"jesus#drinkz.io","name":"... Garcia","password_digest":"...","promotion_ids":[],
"role_id":"56cb596bc226cb5c04efd1cb"}
How I get the response: GET /api/v1/users
def index
#user = User.first
respond_with #user
end
How can I embed roles in the response ?
You'll get the JSON that represents User alone if you don't include the Role as well. You can do something like below
def index
#user = User.first
respond_with(#user, :include => :role)
end
Old school way would be,
def index
#user = User.first
respond_to do |format|
format.json { render :json => #user.to_json(:include => :role) }
end
end
Add gem 'active_model_serializers' to your gemfile if you are not already using it . Then generate an user serializer using
rails generate serializer user
Then add following to app/serializers/user_serializer.rb file.
class UserSerializer < ActiveModel::Serializer
attributes :id, :email,:name, :password_digest, :promotion_ids, :api_key
has_many :roles
end
Related
I have two models (Company and User) that have a belongs_to/has_many relationship.
class Company < ActiveRecord::Base
attr_accessor :users_attributes
has_many :users
accepts_nested_attributes_for :users, allow_destroy: true
end
class User < ActiveRecord::Base
belongs_to :company
end
In my CompaniesController I want to create a new instance of Company along with a group of Users.
class Cms::CompaniesController < ApplicationController
def create
company = Company.new(company_params)
respond_to do |format|
if company.save
format.json { render json: company, status: :ok }
else
format.json { render json: company.errors.messages, status: :bad_request }
end
end
end
private
def company_params
params.require(:company).permit(
:id,
:name,
users_attributes: [
:id,
:_destroy,
:first_name,
:last_name,
:email
]
)
end
end
When I call company.save, I would expect a new instance of Company along with several new instances of User to be saved, depending on how many users I have in my params, however no users are persisted.
Here is a sample of what company_params looks like:
{"id"=>nil, "name"=>"ABC", "users_attributes"=>[{"first_name"=>"Foo", "last_name"=>"Bar", "email"=>"foo#bar.com"}]}
What am I missing here?
Remove attr_accessor:
class Company < ActiveRecord::Base
has_many :users
accepts_nested_attributes_for :users, allow_destroy: true
end
Everything else should work.
--
attr_accessor creates getter/setter methods in your class.
It's mostly used for virtual attributes (ones which aren't saved to the database). Your current setup is preventing you from being able to save the users_attributes param, thus your users are not saving.
I'm using active-model-serializers for my API.
I have a model (Task) that has many subtasks(always Task model), called children.
I do this recursive has_many association thanks to ancestry gem (https://github.com/stefankroes/ancestry)
It works all enough well, but I have this problem:
Task has an association with User, but while active-model-serializers, export user for the main object, it doesn't show user details for also all children.
This is my serializer:
class TaskSerializer < ActiveModel::Serializer
attributes :id, :name, :details, :user_id
belongs_to :user
has_many :children
end
This is my controller:
class Api::V1::TasksController < Api::V1::BaseController
respond_to :json
def index
#tasks = current_user.company.tasks
respond_with #tasks, location: nil
end
end
And this is my model:
class Task < ActiveRecord::Base
has_ancestry
belongs_to :user
end
I've also tried to do this in my model:
class Api::V1::TasksController < Api::V1::BaseController
respond_to :json
def index
#tasks = current_user.company.tasks
render json: #tasks,
each_serializer: TaskSerializer,
status: :ok
end
end
But doesn't work...I've the user details for the parent object, but not for the children(where he only show me user_id, without all User object)
Any suggestions ?
Have you tried adding a serializer for the Children model or querying them as a explicit attribute like so?
class TaskSerializer < ActiveModel::Serializer
attributes :id, :name, :details, :user_id, :children
def children
object.children
end
end
I'm creating a simple newsfeed in rails. The aim is for it to return all the posts from the groups the user is following. I am using socialization for my follow functionality.
The exact error is:
NoMethodError (undefined method `followees' for false:FalseClass)
Here are my basic models not including like and follow as they're empty:
User:
class User < ActiveRecord::Base
authenticates_with_sorcery!
attr_accessible :username, :password, :email
has_many :groups
has_many :posts
acts_as_follower
acts_as_liker
before_create :generate_auth_token
def auth_token_expired?
auth_token_expires_at < Time.now
end
def generate_auth_token(expires = nil)
self.auth_token = SecureRandom.hex(20)
self.auth_token_expires_at = expires || 1.day.from_now
end
def regenerate_auth_token!(expires = nil)
Rails.logger.info "Regenerating user auth_token"
Rails.logger.info " Expiration: #{expires}" if expires
generate_auth_token(expires)
save!
end
end
Group:
class Group < ActiveRecord::Base
attr_accessible :description, :name, :user_id
has_many :posts
belongs_to :user
acts_as_followable
end
Post:
class Post < ActiveRecord::Base
attr_accessible :body, :user_id, :group_id
belongs_to :user
belongs_to :group
acts_as_likeable
end
I have setup a function named newsfeed in my post controller. The function grabs all the groups that a user is following and then grabs all the posts that have group_ids matching group_ids in the returned groups array. But I keep getting unidentified method followees(socialization provides this). Yet it appears to work when using single users and posts in irb.
def newsfeed
#groups = current_user.followees(Group)
#posts = Post.where(:group_id => #groups)
respond_to do |format|
format.html # show.html.erb
format.json { render json: #posts }
end
end
Thanks for any help.
Apparently, your current_user method returns false, instead of a user. Check what's returned from that method, as find out why you get the error...
Your current_user return false instead of instance of User. You may see it from error text.
I am trying to prevent a user from accessing a profile that is not his/hers. My UserProfile model is linked to my profile model and has a column pertaining to the user_id. My thought was use cancan and "if a user.id does not match up with the associated user_id from the user_profile" then reject. I have tried to do this in so many different combinations and permutations and have only gotten cancan to reject if use the id field correlating to the UserProfile.
With the code below I can access
http://localhost:3000/users/8/profile and http://localhost:3000/users/6/profile
so the user has permission to see "use the show method of the UserProfile" of any user. So results are fetching properly but cancan is not limiting permissions based on the current User.id
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user (not logged in)
if user.has_role? :registered
can :show, UserProfile, :user_id => user.id
end
end
end
class UserProfile < ActiveRecord::Base
attr_accessible :DOB, :user_id, :address_city, :address_country, :address_state, :address_street, :address_zip, :avatar, :first_name, :gender, :last_name, :position, :time_zone, :years_played
belongs_to :user
end
class User < ActiveRecord::Base
has_one :user_profile, :dependent => :destroy
end
Route File
get '/users/:user_id/profile/' => "user_profiles#show", :as => :user_profile
UserProfile Controller
class UserProfilesController < ApplicationController
load_and_authorize_resource
def show
##user = User.accessible_by(current_ability)
##user = User.find(params[:user_id])
##profile = #user.user_profile
#profile = UserProfile.where(:user_id => params[:user_id]).first
respond_to do |format|
format.html # show.html.erb
format.json { render :json => #profile }
end
end
end
There are different kinds of users in my system. One kind is, let's say, a designer:
class Designer < ActiveRecord::Base
attr_accessible :user_id, :portfolio_id, :some_designer_specific_field
belongs_to :user
belongs_to :portfolio
end
That is created immediately when the user signs up. So when a user fills out the sign_up form, a Devise User is created along with this Designer object with its user_id set to the new User that was created. It's easy enough if I have access to the code of the controller. But with Devise, I don't have access to this registration controller.
What's the proper way to create a User and Designer upon registration?
In a recent project I've used the form object pattern to create both a Devise user and a company in one step. This involves bypassing Devise's RegistrationsController and creating your own SignupsController.
# config/routes.rb
# Signups
get 'signup' => 'signups#new', as: :new_signup
post 'signup' => 'signups#create', as: :signups
# app/controllers/signups_controller.rb
class SignupsController < ApplicationController
def new
#signup = Signup.new
end
def create
#signup = Signup.new(params[:signup])
if #signup.save
sign_in #signup.user
redirect_to projects_path, notice: 'You signed up successfully.'
else
render action: :new
end
end
end
The referenced signup model is defined as a form object.
# app/models/signup.rb
# The signup class is a form object class that helps with
# creating a user, account and project all in one step and form
class Signup
# Available in Rails 4
include ActiveModel::Model
attr_reader :user
attr_reader :account
attr_reader :membership
attr_accessor :name
attr_accessor :company_name
attr_accessor :email
attr_accessor :password
validates :name, :company_name, :email, :password, presence: true
def save
# Validate signup object
return false unless valid?
delegate_attributes_for_user
delegate_attributes_for_account
delegate_errors_for_user unless #user.valid?
delegate_errors_for_account unless #account.valid?
# Have any errors been added by validating user and account?
if !errors.any?
persist!
true
else
false
end
end
private
def delegate_attributes_for_user
#user = User.new do |user|
user.name = name
user.email = email
user.password = password
user.password_confirmation = password
end
end
def delegate_attributes_for_account
#account = Account.new do |account|
account.name = company_name
end
end
def delegate_errors_for_user
errors.add(:name, #user.errors[:name].first) if #user.errors[:name].present?
errors.add(:email, #user.errors[:email].first) if #user.errors[:email].present?
errors.add(:password, #user.errors[:password].first) if #user.errors[:password].present?
end
def delegate_errors_for_account
errors.add(:company_name, #account.errors[:name].first) if #account.errors[:name].present?
end
def persist!
#user.save!
#account.save!
create_admin_membership
end
def create_admin_membership
#membership = Membership.create! do |membership|
membership.user = #user
membership.account = #account
membership.admin = true
end
end
end
An excellent read on form objects (and source for my work) is this CodeClimate blog post on Refactoring.
In all, I prefer this approach vastly over using accepts_nested_attributes_for, though there might be even greater ways out there. Let me know if you find one!
===
Edit: Added the referenced models and their associations for better understanding.
class User < ActiveRecord::Base
# Memberships and accounts
has_many :memberships
has_many :accounts, through: :memberships
end
class Membership < ActiveRecord::Base
belongs_to :user
belongs_to :account
end
class Account < ActiveRecord::Base
# Memberships and members
has_many :memberships, dependent: :destroy
has_many :users, through: :memberships
has_many :admins, through: :memberships,
source: :user,
conditions: { 'memberships.admin' => true }
has_many :non_admins, through: :memberships,
source: :user,
conditions: { 'memberships.admin' => false }
end
This structure in the model is modeled alongside saucy, a gem by thoughtbot. The source is not on Github AFAIK, but can extract it from the gem. I've been learning a lot by remodeling it.
If you don't want to change the registration controller, one way is to use the ActiveRecord callbacks
class User < ActiveRecord::Base
after_create :create_designer
private
def create_designer
Designer.create(user_id: self.id)
end
end