How can I make a rails authors resource a devise user? - ruby-on-rails

I have setup a rails application with devise on it so users can register and login and they can add posts and other resources based on their roles(Admin,Teacher,Author,Pupil). Admin as access to everything and I am using gem 'cancan' for roles.
if user.role
if user.role.name == "Admin"
can :manage, :all
elsif user.role.name == "Teacher"
can :manage, [Book, Story]
can :read, [Book, Author, Story]
elsif user.role.name == "Author"
can :manage, [Book, Author]
can :read, [Book, Author, Story]
elsif user.role.name == "Pupil"
can :manage, [Story]
can :read, [Book, Author, Story]
elsif user
can :read, :all
end
else
can :read, :all
end
Currently Authors are just added to a book when you create the book. In the backend you just add authors as many as you like and then assign that to a book. If your an admin you can edit authors details and if your an author you can edit your own profile area in your author resource but there is no login for an author to do this at all.
What I want to know is: Is it easy to create a devise user type like author from authors already added to the backend or will they need to be created all over again?
=== Edit below here ====
user.rb
class User < ActiveRecord::Base
belongs_to :role
def confirmation_required?
false
end
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable
has_attached_file :avatar, styles: {
large: "600x450#",
medium: "250x250#",
small: "100x100#"
}, :default_url => "/images/:style/filler.png"
#validates_attachment_content_type :avatar, :content_type => ["image/jpg", "image/jpeg", "image/png", "image/gif"]
validates_attachment_content_type :avatar, :content_type => /\Aimage\/.*\Z/
validates :avatar, :email, :username, :password, presence: true
end
role.rb
class Role < ActiveRecord::Base
has_many :users
end
author.rb
class Author < ActiveRecord::Base
has_many :books, dependent: :destroy
has_many :ideas, dependent: :destroy
accepts_nested_attributes_for :books
accepts_nested_attributes_for :ideas
validates_uniqueness_of :name
has_attached_file :avatar, :styles => { :large => "980x760", :medium => "300x300>", :thumb => "100x100>" }, :default_url => "/images/:style/missing.png"
validates_attachment_content_type :avatar, :content_type => /\Aimage\/.*\Z/
end
Thanks
Mark

You don't need to create separate model(Author) just to handle author logins.
Better approach will be using associations in this case.
#user_role.rb
class UserRole < ActiveRecord::Base
has_many :users
end
#user.rb
Class User < ActiveRecord::Base
belongs_to :user_role
end
Typical user model attributes will be
User(id: integer, email: string, name:string, user_role_id:integer)
user_role model attributes will be
UserRole(id: integer, role: string)
UserRole.create(role: 'Admin')
UserRole.create(role: 'Teacher')
UserRole.create(role: 'Author')
UserRole.create(role: 'Pupil')
then create your author( Let's assume the id for 'Author' role is 3)
user = User.create(name: 'abc', email: 'def#gmail.com', user_role_id: 3)
now, use this user object and go for devise login.
Now to list all the authors of our Application.
#user.rb
def self.all_authors
User.select('users.id, users.name, user_roles.role AS USER_ROLE')
.joins(:user_role).where(user_roles: {role: 'Author'})
end
Now to get all authors just give a call :
User.all_authors #this will list all the users of type 'author'

Related

How can show current_user's friends' posts and what's popular in one record?

I have set up my scopes and all are working as expected but I could find a way to filter the friends posts in one scope.
In the model
scope :popular, ->{ where("cached_votes_up > '20'") } # change this to a much bigger number overtime
scope :following, ->{ where(Post.current_user.following.ids.include? user_id) }
scope :ordered, -> { order(created_at: :desc) }
In the controller
#post = Post.ordered.popular.following.paginate(:per_page => 10, :page => 1)
How can I add the following/friend filtering for a scope so i can merge them with other scopes.
I'm trying to make the page display posts with more than 20 likes and also display friends' posts even if they're not above 20.
Thanks in advance.
EDIT:
class Post < ActiveRecord::Base
include PublicActivity::Common
cattr_accessor :current_usercontroller.current_user}
scope :popular, ->{ where("cached_votes_up > '1'") } # change this to a much bigger number overtimeuser_id) }
scope :ordered, -> { order(created_at: :desc) }
acts_as_votable
has_attached_file :image, styles: { medium: "550", thumb: "100x100>" }, default_url: "/images/:style/missing.png"
validates_attachment_content_type :image, content_type: /\Aimage\/.*\Z/
belongs_to :user
belongs_to :category
validates :user_id, presence: true
validates :image, presence: true
default_scope { order("created_at DESC")}
has_many :comments
is_impressionable # :counter_cache => true, :column_name => :my_column_name, :unique => true
def previous_post
self.class.where("created_at < ?", created_at).order(created_at: :desc).first
end
def next_post
self.class.where("created_at > ?", created_at).order(created_at: :asc).last
end
end
and relationships.rb
class Relationship < ActiveRecord::Base
belongs_to :follower, class_name: "User"
belongs_to :followed, class_name: "User"
validates :follower_id, presence: true
validates :followed_id, presence: true
end
and the user.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
include PublicActivity::Common
acts_as_voter
is_impressionable
has_attached_file :image, :styles => { :medium => "300x300>", :thumb => "100x100#" }, :default_url => "missing.jpg"
has_attached_file :cover, :styles => { :medium => "300x300>", :thumb => "100x100#" }, :default_url => "missing.jpg"
has_many :posts, dependent: :destroy
has_many :active_relationships, class_name: 'Relationship', foreign_key: "follower_id", dependent: :destroy
has_many :passive_relationships, class_name: 'Relationship', foreign_key: "followed_id", dependent: :destroy
has_many :following, through: :active_relationships, source: :followed
has_many :followers, through: :passive_relationships, source: :follower
has_many :comments
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
validates_attachment :image, :cover,
content_type: { content_type: ["image/jpeg", "image/gif", "image/png"] }
def follow(other)
active_relationships.create(followed_id: other.id)
end
def unfollow(other)
active_relationships.find_by(followed_id: other.id).destroy
end
def following?(other)
following.include?(other)
end
end

Rails: List of users who upvoted

In my rails application I have an upvote system, it allows people to upvote a pin. Then when a user upvoted a pin I render a list of upvoted pins in the user profile. What I want to do know is to provide a list of the users who upvoted a specific pin.
app/controller/pins_controller.rb
def upvote
#pin = Pin.find(params[:id])
if #pin.votes.create(user_id: current_user.id)
flash[:notice] = "Thank you for upvoting! You can upvote a startup only once."
redirect_to(pins_path)
else
flash[:notice] = "You have already upvoted this!"
redirect_to(pins_path)
end
end
app/controller/users_controller.rb
def show
#user = User.find(params[:id])
#pins_for_user = []
#user.votes.each do |vote|
#pins_for_user << vote.pin
end
end
app/models/pin.rb
class Pin < ActiveRecord::Base
belongs_to :user
has_many :votes, dependent: :destroy
has_many :upvoted_users, through: :votes, source: :user
has_many :rewards, dependent: :destroy
has_many :rewarded_users, through: :rewards, source: :user
has_attached_file :image, :styles => { :medium => "300x300>", :thumb => "100x100>" }
has_attached_file :logo, :styles => { :medium => "300x300>", :thumb => "100x100>" }
end
app/models/user.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :pins
has_many :votes, dependent: :destroy
has_many :upvoted_pins, through: :votes, source: :pin
has_many :rewards, dependent: :destroy
has_many :rewarded_pins, through: :rewards, source: :pin
end
app/models/vote.rb
class Vote < ActiveRecord::Base
belongs_to :user
belongs_to :pin, counter_cache: true
validates_uniqueness_of :pin_id, scope: :user_id
end
I was thinking of using #pin.upvoted_users to provide this list but I didn't succeeded to implement it correctly, any ideas?

Rails: list of pins that a user upvoted

I have a rails app with a basic set up to allows users to upvote pins, those pins are ordered from the most upvoted to the less upvoted. What I would like to do now is to render the lists of pins that a user upvoted on his profile.
Here is my config:
app/controllers/pins_controllers.rb
def upvote
#pin = Pin.find(params[:id])
if #pin.votes.create(user_id: current_user.id)
flash[:notice] = "Thank you for upvoting! You can upvote a startup only once."
redirect_to(pins_path)
else
flash[:notice] = "You have already upvoted this!"
redirect_to(pins_path)
end
end
app/models/pin.rb
class Pin < ActiveRecord::Base
belongs_to :user
has_many :votes, dependent: :destroy
has_many :upvoted_users, through: :votes, source: :user
has_attached_file :image, :styles => { :medium => "300x300>", :thumb => "100x100>" }
has_attached_file :logo, :styles => { :medium => "300x300>", :thumb => "100x100>" }
end
app/models/user.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :pins
has_many :votes, dependent: :destroy
has_many :upvoted_pins, through: :votes, source: :pin
end
app/models/vote.rb
class Vote < ActiveRecord::Base
belongs_to :user
belongs_to :pin, counter_cache: true
validates_uniqueness_of :pin_id, scope: :user_id
end
And my routes.rb
resources :pins do
member do
post 'upvote'
end
end
Do you have any ideas how I could do that?
You can get the pins a user #user upvoted for example by the following:
#pins_for_user = []
#user.votes.each do |vote|
#pins_for_user << vote.pin
end
You can embedd this in your user controller, for example in the show method.
Then you can refer to #pins_for_user in your show view (show.html.erb) and display it by:
<% #pins_for_user.each do |pin| %>
<%= pin.name %> # or any other code to display that special pin
<% end %>

Rails has_many belongs_to nil issue

I'm a Rails beginner and I'm currently adding some basic associations to my models. I have the following in my two models:
User model:
class User < ActiveRecord::Base
has_many :photos, dependent: :destroy
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
validates_uniqueness_of :username
end
Photos model:
class Photo < ActiveRecord::Base
belongs_to :user
has_attached_file :image,
styles: { medium: '300x300>', thumb: '100x100>' },
default_url: '/images/:style/missing.png'
validates_attachment_content_type :image, content_type: /\Aimage\/.*\Z/
end
After adding the above, I ran the appropriate migrations:
rails g migration AddUserIdToPhotos user_id:integer
rake db:migrate
The user_id was added to the Photos table but when I add a new photo, the user_id field is set to nil.
When I went to psql to double check there, it does not even show nil, just an empty field.
This is the code in the Photos Controller:
def create
photo = Photo.new(photo_params)
if photo.save
Pusher['the_force'].trigger('new_photo', {
url: photo.image.url(:medium),
description: photo.description,
id: photo.id
})
end
redirect_to '/'
end
private
def photo_params
params.require(:photo).permit(:image, :description, :user_id)
end
end
Any help here would be much appreciated.
If you are not passing the user from your form and you wants to save the user that is already logged in, you have to pass it when creating the photo instance.
photo = Photo.new(photo_params, :user => current_user)

What's an efficient way of associating Post, Comment, User and Vote models in Rails?

Right now, I have three models Post, Comment and User (using Devise) associated as follows:
post.rb:
class Post < ActiveRecord::Base
attr_accessible :title, :content, :total_votes
validates :title, :presence => true,
:length => { :maximum => 30 },
:uniqueness => true
validates :content, :presence => true,
:uniqueness => true
belongs_to :user
has_many :comments, :dependent => :destroy
end
comment.rb:
class Comment < ActiveRecord::Base
attr_accessible :content, :user_id
belongs_to :post, :counter_cache => true
belongs_to :user
end
user.rb:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:omniauthable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :username
validates_presence_of :username
has_many :posts, :dependent => :destroy
has_many :comments, :dependent => :destroy
def self.find_for_facebook_oauth(access_token, signed_in_resource=nil)
data = access_token.extra.raw_info
if user = User.where(:email => data.email).first
user
else # Create a user with a stub password.
User.create!(:email => data.email, :password => Devise.friendly_token[0,20])
end
end
end
I want to add a fourth model called Vote with the following conditions:
Both posts and comments can be voted (up and down) and show the total/sum.
Each post will have many votes (up and down) and show the total/sum.
Each comment will have many votes
The ID of the user should be stored each time he or she votes so I can restrict one vote per user and show the ID/name of the users who voted (not sure where to store it)
Now, I'm not sure if this is a good occasion to use polymorphic associations and/or counter cache.
What's an efficient way of associating these Post, Comment, User and Voting models?
(If possible, I would like to see how the migration would look like)
This is a perfect textbook example of where a polymorphic association would be useful.
Your votes table migration would look like this:
create_table :votes do |t|
t.references :votable, :polymorphic => true
t.references :user
t.integer :polarity
t.integer :total
end
This would create a table with this schema:
id INTEGER
votable_id INTEGER
votable_type VARCHAR
user_id INTEGER
polarity INTEGER
total INTEGER
Here, user_id would be the person who cast the vote, polarity would be either '1' for an upvote or '-1' for a downvote (this lets you just sum the polarities to get upvotes and downvotes to cancel), votable_type would contain what the vote is for (Post or Comment), votable_id would contain the id of the thing the vote is for, and total would keep a running total of the vote sum (for efficiency).
Then your models would look like this:
class Vote < ActiveRecord::Base
belongs_to :votable, :polymorphic => true
belongs_to :user
before_create :update_total
protected
def update_total
self.total ||= 0
self.total += self.polarity
end
end
class Post < ActiveRecord::Base
has_many :votes, :as => :votable
end
class Comment < ActiveRecord::Base
has_many :votes, :as => :votable
end
class User < ActiveRecord::Base
has_many :votes
end

Resources