My problem: User has_one Profile. When new User is created, APP also automatically creates Profile, which belongs to User. I tried to do it through controller, through callback, always same error (Stack level too deep). My models:
class User < ActiveRecord::Base
has_secure_password
attr_accessible :email, :password, :password_confirmation
validates_uniqueness_of :email, :case_sensitive => false
validates :email, :email_format => true
validates :password, :length=> {:in=> 5...32}
validates :email, :password, :password_confirmation, :presence =>true
has_many :authentications
has_many :tests
has_many :answers
has_many :results
has_one :profile
#after_create :build_profile
#tried this way
def build_profile
self.build_profile
end
end
#
class Profile < ActiveRecord::Base
attr_accessible :user_id
belongs_to :user
end
#
def create
#user = User.new(params[:user])
#user.email=#user.email.downcase
if #user.save
session[:user_id] = #user.id
#profile=#user.build_profile
redirect_to root_url, notice: "Thank you for signing up!"
else
render "new"
end
end
Alsways same error. Why?
def build_profile
self.build_profile
end
This loops endlessly (and I can't see the point, what did you want to do?)
you should simply remove the build_profile method (don't worry, it's defined thanks to the association).
user = User.new
user.build_profile
|_ calls self.build_profile, but self is user
|_ calls user.build_profile
|_ ...
Related
What is the best approach to combine information from two different tables on Ruby on Rails, when building a JSON for Web Services purpose?
I want to combine my list of clients with a tag that is taken from another table than users table.
Here is how I proceed from the controller
def clients
#orders = #bar.orders
#users = User.where(id: #orders.pluck(:user_id).uniq).all
#tags = UserTag.where(bar: #bar, user_id: #orders.pluck(:user_id).uniq).all
end
The view is built this way
json.user_tags do
json.array!(#tags) do |user_tag|
json.extract! user_tag, :id, :bar_id, :user_id, :tag
end
end
json.users do
json.array!(#users) do |user|
json.extract! user, :id, :first_name, :last_name, :email, :facebook_id, :context, :created_at, :updated_at, :company, :phone, :birthdate, :stripe_customer_id, :bar_id, :role
end
end
The JSON generated with this code looks like this
I would like to integrate the tag field directly in users array, next to other users information such as on this illustration
The UserTag model is built like that
class UserTag < ActiveRecord::Base
belongs_to :user, :counter_cache => true
belongs_to :bar
validates_uniqueness_of :bar_id, :user_id, :scope => :bar_id
acts_as_paranoid without_default_scope: true
def self.default_scope
with_deleted
end
def api_error_message
errors.full_messages.join("\n")
end
end
And User model:
class User < ActiveRecord::Base
has_many :access_tokens, dependent: :destroy
belongs_to :club
belongs_to :bar
enum role: [:user, :club_owner, :waiter, :admin]
has_many :club_comments
has_many :club_subscriptions
has_many :artist_subscriptions
has_many :artist_votes
has_many :payments
has_many :carts
has_many :user_entrances
has_many :bookings, through: :user_entrances
has_many :booking_events, through: :user_entrances
has_many :cart_item_consumptions
has_many :clientlist_elements
has_secure_password
has_one :address, as: :addressable
accepts_nested_attributes_for :address
validates :password, length: {minimum: 8}, if: :validate_password?
validates :password_confirmation, presence: true, if: :validate_password?
validates :email, presence: true, if: :user_context_email
validates :email, email: true, if: :user_context_email
validates :email, :facebook_id, uniqueness: true, :allow_blank => true, :allow_nil => true
validates :first_name, presence: true
validates :last_name, presence: true
reverse_geocoded_by :latitude, :longitude
after_create :create_access_token
after_save :update_vote_position_if_needed
def validate_password?
password.present? || password_confirmation.present?
end
def name
"#{first_name.capitalize} #{last_name.capitalize}"
end
def create_access_token
AccessToken.create(user: self)
end
def user_context_email
context == 0
end
def user_context_fb
context == 1
end
def update_vote_position_if_needed
if self.latitude_changed? || self.longitude_changed?
self.delay.update_vote_position
end
end
def update_vote_position
self.artist_votes.each do |vote|
vote.latitude = self.latitude
vote.longitude = self.longitude
vote.save
end
end
def stripe_description
"#{first_name} #{last_name} - #{email}"
end
def stripe_customer_metadata
{"User_id" => self.id, "Firstname" => self.first_name, "Lastname" => self.last_name, "Email" => self.email, "Phone" => self.phone}
end
def api_error_message
errors.full_messages.join("\n")
end
end
EDIT
I tried the #krishnar solution, here is how the JSON looks like now
The users are duplicated and only users with tag appear (we need to display all users even those without tags)
Modify user model to have association:
class User < ActiveRecord::Base
# define user to user_tags association
has_many :user_tags
end
Join users table with user_tags and select user_tags id as tag to use in json file:
def clients
#orders = #bar.orders
#users = User.where(id: #orders.pluck(:user_id).uniq).joins("left join user_tags on users.id=user_tags.user_id and user_tags.bar_id='#{#bar.id}'").select("users.*","user_tags.id as tag")
#tags = UserTag.where(bar: #bar, user_id: #orders.pluck(:user_id).uniq).all
end
Now you can access tag in #users array:
json.users do
json.array!(#users) do |user|
json.extract! user, :id, :first_name, :last_name, :email, :facebook_id, :context, :created_at, :updated_at, :company, :phone, :birthdate, :stripe_customer_id, :bar_id, :role, :tag
end
end
I'm trying to create an user register using two models User and profile, nested strong parameters in one controller. when I send parameter I get this error unknown attribute 'profiles_attributes' for User. and I can't create user neither profile :
class User < ActiveRecord::Base
has_one :profile
has_many :apartments
has_many :session
has_secure_password
validates :email, presence: true, uniqueness: true
validates :password, presence: true
accepts_nested_attributes_for :profile
end
class Profile < ActiveRecord::Base
belongs_to :user
belongs_to :city
has_many :profile_universities
has_many :universities, through: :profile_universities
has_many :profile_preferences
has_many :preferences, through: :profile_preferences
has_one :photo, :as => :imageable
end
class Api::V1::UserController < ApplicationController
before_action :user_params
def create_without_facebook
#user= User.new(user_params)
if #user.save
#profile = Profile.new(user_params[:profiles_attributes])
render json: [#user, #profile]
else
render json: #user.errors, status: :unprocessable_entity
end
end
def user_params
params.require(:user).permit(:email, :password, profiles_attributes: [:first_name, :last_name, :birthday, :gender, :marital_status, :ocupation, :budget, :question, :about, :city])
end
end
use the singular profile_attributes if it's a has_one
I'm creating a blog on Rails with posts, users(authentication with Devise), comments. If user will write comment to post I want to show his name above his comment. How can I do this? Please, help me
My comments controller:
class CommentsController < ApplicationController
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.build(params[:comment])
#comment.save
redirect_to #post
end
def destroy
#comment = Comment.find(params[:id])
#comment.destroy
redirect_to #comment.post
end
end
My models:
class Comment < ActiveRecord::Base
attr_accessible :post_id, :text
belongs_to :post
belongs_to :user
end
class User < ActiveRecord::Base
has_many :posts, :dependent => :destroy
has_many :comments, :dependent => :destroy
validates :fullname, :presence => true, :uniqueness => true
validates :password, :presence => true
validates :email, :presence => true, :uniqueness => true
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :email, :password, :password_confirmation, :fullname
end
class Post < ActiveRecord::Base
attr_accessible :text, :title, :tag_list
acts_as_taggable
validates :user_id, :presence => true
validates :title, :presence => true
validates :text, :presence => true
belongs_to :user
has_many :comments
end
Just assign the user in comments_controller.rb
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.build(params[:comment])
#comment.user = current_user
#comment.save
redirect_to #post
end
Next time spend a little more time researching your question, this is a common task and a very brief Google search would have saved you the trouble of asking.
I am trying to use invitations for my site . I want to know that ; My first User can't need an invitation ? How can I make an exception? I can guess that ,
I must use a rescue exception but I dont know where it must be done?
My users.rb model:
class User < ActiveRecord::Base
attr_accessible :nickname, :email, :password, :password_confirmation, :invitation_token
has_secure_password
has_many :friendships
has_many :friends, :through => :friendships
has_many :inverse_friendships, :class_name => "Friendship", :foreign_key => "friend_id"
has_many :inverse_friends, :through => :inverse_friendships, :source => :user
has_many :topics, dependent: :destroy
has_many :posts, dependent: :destroy
before_save { |user| user.email = email.downcase }
before_save { |user| user.nickname = nickname.downcase }
before_save :create_remember_token
validates :nickname, presence: true, length: { maximum: 150 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true,
format: { with: VALID_EMAIL_REGEX },
uniqueness: {case_sensitive: false }
validates :password, presence: true, length: { minimum: 6 }
validates :password_confirmation, presence: true
validates_presence_of :invitation_id, :message => 'gerekli'
validates_uniqueness_of :invitation_id
has_many :sent_invitations, :class_name => 'Invitation', :foreign_key => 'sender_id'
belongs_to :invitation
before_create :set_invitation_limit
def invitation_token
invitation.token if invitation
end
def invitation_token=(token)
self.invitation = Invitation.find_by_token(token)
end
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
def set_invitation_limit
self.invitation_limit = 5
end
end
And this is the users_controller.rb:
def new
#user = User.new(:invitation_token => params[:invitation_token])
#user.email = #user.invitation.recipient_email if #user.invitation
end
def create
#user = User.new(params[:user])
if #user.save
sign_in #user
flash[:success] = "Giripedia'ya hoşgeldiniz'!"
redirect_to #user
else
render 'new'
end
end
Make a conditional validation. Let me give you a short example:
class User
# ...
validates_presence_of :invitation_id, :if => :invitation_needed?
# An invitation is needed if there is at least one user. If there
# are no users, there can't be an invitation.
def invitation_needed?
User.all.count >= 1
end
end
Details: See the manual on conditional validation
I m not sure if this is a good idea to write a conditional validation just to be able to save your first user.
You dont want to do a count query every time you are validating a user.
You can save your first user from console with skip validation option.
#user.save(:validate => false)
I have a has_many :through relationship between users and projects via an ownership join model. I want to be able to set an attribute of the ownership model while creating a relationship between a user and a new project. Here is what I have so far:
def create
#project = Project.new(params[:project])
if #project.save
current_user.projects << #project
flash[:success] = "Project created!"
redirect_to #project
else
flash[:error] = "Project not created."
end
end
Basically, I don't know how to set the value "owner_type" in the ownership model when creating a new project for a given user since I don't directly mention the ownership join model in the project creation controller. How do I do that?
Here is my ownership (join) model:
class Ownership < ActiveRecord::Base
attr_accessible :owner_type
belongs_to :project
belongs_to :user
validates :user_id, :presence => true
validates :project_id, :presence => true
validates :owner_type, :presence => true
end
and my User model:
class User < ActiveRecord::Base
attr_accessible :name, :email, :admin, :projects
has_many :ownerships
has_many :projects, :through => :ownerships
accepts_nested_attributes_for :projects
and my Project model:
class Project < ActiveRecord::Base
attr_accessible :name, :description
has_many :ownerships
has_many :users, :through => :ownerships
The key is that you build (not create) the association before you hit #project.save when you hit save the project is persisted first and if it was persisted successfully, the ownership will be created too.
def create
#project = Project.new(params[:project])
#project.ownerships.build(:user => current_user, :owner_type => 'chief')
if #project.save
flash[:success] = "Project created!"
redirect_to #project
else
flash[:error] = "Project not created."
end
end
EDIT: This didn't actually work for me.
In my user model I allow for nested attributes with this line:
accepts_nested_attributes_for :projects
Then, in my projects#create controller action, I nested an attribute while creating the association between the user and the new project as so:
current_user.ownerships.create(:owner_type => 'designer', :project => #project)
To be honest I'm not sure exactly why this works but it does. Would be awesome for someone else to explain it.