How to get the right id before create in rails - ruby-on-rails

I'm expanding upon M.Hartl's Sample twitter app.
What I've done is created a new model called Books. I want the books to be followable, like users, so if you are following a book you will see all comments associated with that book in your feed.
I have had minor success in creating the model, and following it. I can follow the book, say with id "2" and have the posts show in the feed. though when I try follow a user with id 2, I end up following book id "2" or get the UNIQUE constraint failed in my console. Another strange thing, if I destroy the relationship with both book and id "2" and just follow user "2", I actually get the users posts, though I can't unfollow the user from his button, I have to go to book "2" and unfollow from there.
Any ideas?
I'm thinking I need to have an if else check in my .create to make sure if Im on a book page I follow a book and not a user before committing to the database.
Any help or thoughts would be greatly appreciated.
here's some relevant code:
class User < ActiveRecord::Base
def feed
following_ids_subselect = "SELECT followed_id FROM relationships
WHERE follower_id = :user_id"
Micropost.where("book_id IN (#{following_ids_subselect})
OR user_id = :user_id", user_id: id)
end
# Follows a user.
def follow(other_user)
active_relationships.create(followed_id: other_user.id)
end
# Follows a book.
def follown(book)
active_relationships.create(followed_id: book.id)
end
# Unfollows a user.
def unfollow(other_user)
active_relationships.find_by(followed_id: other_user.id).destroy
end
# Unfollows a book.
def unfollown(book)
active_relationships.find_by(followed_id: book.id).destroy
end
# Returns true if the current user is following the other user.
def following?(other_user)
following.include?(other_user)
end
# Returns true if the current user is following the book.
def followingn?(book)
following.include?(book)
end
class RelationshipsController < ApplicationController
def create
#user = User.find(params[:followed_id])
if current_user.follow(#user)
else
#book = Book.find(params[:followed_id])
current_user.follown(#book)
end
# respond_to do |format|
# format.html { redirect_to #user }
# format.js
# end
end
class Relationship < ActiveRecord::Base
belongs_to :follower, class_name: "User"
belongs_to :followed, class_name: "User"
belongs_to :followed, class_name: "Book"
validates :follower_id, presence: true
validates :followed_id, presence: true
end

Related

Create record for another model when account is created?

I have a multi-tenant application. When an account is created, the account belongs to an owner and also creates a user record for the owner. This owner can invite other users through a memberships join table. All users except for account owners have memberships to the account.
For users with memberships (not owners of accounts) the account/users/:id show page shows up. I would like the same for account owners, but am receiving the following error message:
ActiveRecord::RecordNotFound in Accounts::UsersController#show
Couldn't find User with 'id'=2 [WHERE "memberships"."account_id" = $1]
def show
#user = current_account.users.find(params[:id])
end
I can add a membership to the owner user in the admin panel and this error goes away, however I would like to add the membership to the owner/user when they create their account.
Any ideas?
Adding #account.memberships.build(user_id: current_user, account_id: current_account) before if #account.save in the accounts controller below does not seem to work.
controllers
user.rb
module Accounts
class UsersController < Accounts::BaseController
before_action :authorize_owner!, only: [:edit, :show, :update, :destroy]
def show
#user = current_account.users.find(params[:id])
end
def destroy
user = User.find(params[:id])
current_account.users.delete(user)
flash[:notice] = "#{user.email} has been removed from this account."
redirect_to users_path
end
end
end
accounts_controller.rb
class AccountsController < ApplicationController
def new
#account = Account.new
#account.build_owner
end
def create
#account = Account.new(account_params)
if #account.save
sign_in(#account.owner)
flash[:notice] = "Your account has been created."
redirect_to root_url(subdomain: #account.subdomain)
else
flash.now[:alert] = "Sorry, your account could not be created."
render :new
end
end
private
def account_params
params.require(:account).permit(:name, :subdomain,
{ owner_attributes: [:email, :password, :password_confirmation
]}
)
end
end
Models
user.rb
class User < ApplicationRecord
has_many :memberships
has_many :accounts, through: :memberships
def owned_accounts
Account.where(owner: self)
end
def all_accounts
owned_accounts + accounts
end
end
account.rb
class Account < ApplicationRecord
belongs_to :owner, class_name: "User"
accepts_nested_attributes_for :owner
validates :subdomain, presence: true, uniqueness: true
has_many :memberships
has_many :users, through: :memberships
end
membership.rb
class Membership < ApplicationRecord
belongs_to :account
belongs_to :user
end
Have you tried callback after_create?
If it works, you will need to figure it on client and admin create an account, self assigning (admin) against on create assigning (client).
# models/account.rb
after_create do
self.memberships.create(user_id: self.owner, account_id: self.id)
end
Ended up answering this question by putting this line under if #account.save:
if #account.save
#account.memberships.create(user_id: #account.owner.id, account_id: #account.id)
Probably not ideal, but it works for now. I might end up making a service or something like that for it, though.

Assign User to a Company on sign up

Let's say I have a User model:
class User
has_secure_password
belongs_to :company, required: true
end
And a Company model:
class Company
has_many :users, dependent: :destroy
end
I wand to create a form that assigns the User to a Company, either a new one if my app doesn't have a record with that company name, or a pre-existing Company.
This is what I have so far, but I am sure there is dryer method...
class UsersController
def create
user = User.new(user_params)
user.company = Company.find_by_name(params['company']) || Comapny.create(name: params['company'])
if user.save
redirect_to root_path
else
redirect_to singup_path
end
end
end
Thanks!
You could use first_or_create:
user.company = Company.where(name: params['company']).first_or_create
...which basically does what it says on the tin.

Passing in, retrieving, and setting restrictions of User from Post - Comment model in Rails

I'm attempting to set limits on the amount of commenting users can do on particular post during the day. I have implemented the following (successfully) in my Post model to limit the amount of Posts they can create.
class Post < ActiveRecord::Base
validate :daily_limit, :on => :create
def daily_limit
# Small limit for users who just sign up
if author.created_at >= 14.days.ago
if author.created_posts.today.count >= 4
errors.add(:base, "Exceeds Your Daily Trial Period Limit(4)")
end
else
if author.created_posts.today.count >= author.post_limit_day
errors.add(:base, "Exceeds Your Daily Limit")
end
end
end
end
But, when I attempt to add similar restrictions to my Comment model
class PostComment < ActiveRecord::Base
validate :daily_limit, :on => :create
belongs_to :post, :counter_cache => true
belongs_to :user
def daily_limit
# Small limit for users who just sign up
if user.posted_comments.today.count >= 2
errors.add(:base, "Exceeds Your Daily Trial Period Limit(4)")
end
end
end
I am greeted with a undefined method 'posted_comments' for nil:NilClass error. I don't believe my user_id is being passed into my model correctly in order to access it with something like user.posted_comments.today.count>=2
My create action in my post_comments controller is as follows:
class PostCommentsController < ApplicationController
def create
#post = Post.find(params[:post_id])
#post_comment = #post.post_comments.create(post_comment_params)
#post_comment.user = current_user
if #post_comment.save
redirect_to #post
else
flash[:alert] = "Comment Not Added"
redirect_to #post
end
end
end
and the my hacked down User model is as follows:
class User < ActiveRecord::Base
has_many :created_posts, class_name: 'Post', :foreign_key => "author_id",
dependent: :destroy
has_many :posted_comments, class_name: 'PostComment', :foreign_key =>"user_id", dependent: :destroy
end
Thanks.
You are assigning the user after "create" in your controller
#post_comment = #post.post_comments.create(post_comment_params)
#post_comment.user = current_user
Try this:
#post_comment = #post.post_comments.build(post_comment_params)
#post_comment.user = current_user

Newsfeed in Rails, unidentified method

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.

validates_each user_id & question_id stops collection of user_id but not creation of record

I am trying to limit a user of my application to voting (liking in this case) a an answer to a question a particular number of times. I am successfully stopping the collection of the user_id but the record keeps getting created. I need for the validation to actually block the creation of the record in the likes table.
alt text http://gadocidesign.squarespace.com/storage/Screen%20shot%202010-05-20%20at%2010.07.19%20AM.png
As you can see the last two votes lose the user_id but are still created. The code below will show you how I am doing this. I am trying to limit a user to voting no more than 10 times on any answer to a question.
Like Model (I spare you the reverse has_many associations but they are there).
class Like < ActiveRecord::Base
belongs_to :site
belongs_to :user
belongs_to :question
validates_each :user_id do |row, attr, value|
m.errors.add :user_id, 'Too many likes' unless row.like_count < 10
end
def like_count
Like.count(:conditions => {:user_id => user_id, :question_id => question_id})
end
end
LikesController#create
class LikesController < ApplicationController
def create
#user = current_user
#site = Site.find(params[:site_id])
#like = #site.likes.create!(params[:like])
#like.user = current_user
#like.save
respond_to do |format|
format.html { redirect_to #site}
format.js
end
end
end
You're telling it to do exactly what you're seeing.
# This is what creates the record you're seeing in your db.
#like = #site.likes.create!(params[:like])
# And now you try to assign the user.
#like.user = current_user
#like.save
Try something like this instead:
#like = #site.likes.create!(params[:like].merge(:user_id => #user.id))

Resources