First here's my current setup:
models/user.rb
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable
has_many :events
end
models/event.rb
class Event < ActiveRecord::Base
belongs_to :user
end
So, this works in the sense that a user have many events that s/he can CRUD. Anyone that is not logged in can only view and list all the events.
From this initial setup, I now have another set of users that are attendees and the current users are now actually event managers instead of just a generic user. Essentially, I now have two models that are both users (since they can both log in/sign up and have the same fields) and I was thinking that event should read something like:
models/event.rb
class Event < ActiveRecord::Base
belongs_to :manager
has_many :attendees, :through => :attendance # attendance is a join model
end
but I don't want to create a separate table for managers and attendees and I was thinking of sub classing the user model but I'm not particularly sure about how to go about it. I was looking into the :as and :polymorphic parameters in AR but I'm still not quite sure on how to do it. Help?
What you are looking for is called Single Table Inheritance. Here is one resource on the subject. There are many more. Just google for "Rails Single Table Inheritance".
Related
In Rails, how would one conditionally associated records on a has_many_through relationship? Using the following Rails docs example:
class Physician < ApplicationRecord
has_many :appointments
has_many :patients, through: :appointments
end
class Appointment < ApplicationRecord
belongs_to :physician
belongs_to :patient
end
class Patient < ApplicationRecord
has_many :appointments
has_many :physicians, through: :appointments
end
Suppose I wanted to have an appointment reference exactly two physicians. That is, there will not be any appointment record one there is less than two physicians assigned. However, how could that appointment then reference each physician?
Example
Basically, I want to keep track of users liking other users and mutual likes between them. A connection is established when both users like each other. But I don't want a connection when only one user likes another but it is not reciprocal.
When User A likes User B. A "like" is created.
When User B likes User A. A "like" is created. A "connection" is also created.
The connection should be able to call:
connection.users
The user should be able to call:
user.likes
user.connections
The problem that I'm having is how can that relationship table know when it is mutual?
For the original question, a connection doesnt make a difference between the two users, so i would model it as a one to many relationship and validate it only has two users.
A like has two users, the liker (giver of the like) and the likee (receiver of the like). Every time you create new like, you should check if the likee also likes the liker. If likee.likes.where(likee: liker)? If yes, then create the new connection with both users.
class User < ApplicationRecord
has_many :likes
has_many :connections
end
class Like < ApplicationRecord
belongs_to :user, :foreign_key => 'liker_id'
belongs_to :user, :foreign_key => 'likee_id'
end
class Connection < ApplicationRecord
has_many :likes
has_many :users, through: likes
end
I want to add that i am not 100% sure of this as i am currently learning Rails myself. But this is what I came up with and hopefully its useful (and correct).
I'm new to Rails 5 and I'm trying to model the following scenario using Devise and CanCanCan: a store application.
Relevant figures are: Admin, StoreManager, StoreOfficer, Customer, Technician.
Admin creates StoreManager.
StoreOfficer can create Customer's information to register new Customers.
StoreOfficer can see the complete list of all Customers with relative information
StoreOfficer can see the complete list of all Technicians with relative information
StoreManager can see the complete list of all StoreOfficers with relative information
StoreManager can enable StoreOfficers to use the system and edit their information
StoreManager can enable Customers created by StoreOfficers to use the system
StoreManager can see the complete list of all Customers with relative information
There are also some other paths, but it's possible for me to develop them as these presented cases are done.
Any help/tutorial please?
Thanks,
FZ
After trying some different things, I created the following satisfying schema, which I post here for others so that they can use something solid:
Class User<ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
belongs_to :userable, polymorphic: true
end
Then all the other roles classes similar to the following one:
class Customer < ApplicationRecord
belongs_to :technician
belongs_to :store_officer
has_one :user, as: :userable, dependent: :destroy
has_one :address, as: :addressable, dependent: :destroy
accepts_nested_attributes_for :user, :address
end
Accordingly, I created all the needed fields using migrations in the database.
Then I put in every controller the code before_action :authenticate_user!.
After populating the db a bit, I can now login with different users inserted using rake db:seed.
This is my routes.rb file:
Rails.application.routes.draw do
devise_for :users
resources :store_managers
resources :store_officers
resources :items
resources :technicians
resources :customers
resources :addresses
resources :users
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
What do you all think about this setup?
Now I want to introduce CanCanCan to my project. Please validate the following steps I'm going to do:
Run rails g cancan:ability
Put all the rules in the ability.rb file:
if user.admin?
can :manage, :all
elsif user.store_manager?
can :read, Customer
can :create, Customer
can :update, Item do |item|
item.try(:user) == user
end
can :destroy, Item do |item|
item.try(:user) == user
end
elsif user.store_officer?
can :read, Customer
end
.
.
.
Create the methods in user.rb model to check roles:
def customer?
self.userable_type == Customer
end
Put load_and_authorize_resource in every controller
Do you think this approach is the correct one? Or maybe I should put methods/definitions in other files?
Thanks,
FZ
I'm using Devise to manage user model.
Here's the User model, user.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
acts_as_voter
has_many :topics
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
Here's the Topics model, topic.rb
class Topic < ActiveRecord::Base
acts_as_voteable
belongs_to :user
end
When I create a post, the user ID is stored in the "user_id" column of Topics. I want to a User profile page, which should display all the posts he has made. In my User profile page view, I have,
<%= Topic.find_by_user_id(#user.id) %>
I have two posts made by the same user,
But when I try fetch all the posts made by the user, the SQL command automatically queries with a LIMIT of 1. Like this,
And because of this, the view is fetching only 1 post made by the user. How do I fetch all the posts?
find_by_attribute will always return only one result. You need to change your code to:
Topic.where(user_id: #user.id)
or even better:
#user.topics
I'm using Devise for authentication with two custom fields added = :organization_id and :username. I also generated a scaffold for the Organization which simply consists of Name.
Currently when users sign up they can type in an Organization ID (integer) and a username (string).
Users belong_to organizations, and organizations has_many users.
Here's what my models look like (I left everything else untouched except for the files inside app/views/devise/registrations to add organization_id and username):
#user.rb
class User < ActiveRecord::Base
belongs_to :organization
# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :organization_id, :username
end
#organization.rb
class Organization < ActiveRecord::Base
has_many :users
end
What I would like is for an organization to be automatically created when a user signs up without the user having to specify the organization_id.
Also, ideally the #organization.name would be exactly the same as :username
How would I go about doing this?
I've seen the Railscast on nested model forms but he's creating a question inside the survey form, and questions belong to a survey. I need to do it the other way around (create an organization inside the user form, where users belong to a survey.)
Any help and suggestions would be greatly appreciated..
class User < ActiveRecord::Base
before_create :create_organization
private
def create_organization
self.organization = Organization.create :name => self.username
end
end
The create_organization method will be executed right before the sql query which creates the user. It'll create a new organization and assign it to the user.
Going back to an example I had previously asked about, I'll try and make this question as simple as possible.
Supposed I have User and Document models.
A User has_many Documents and a Document belongs_to a User. This relationship works fine today.
I want to introduce an Edits model that belongs_to a Document and belongs_to a User. The User can be any user, not necessary the one who created the document. With this new model, the Document now has_many :edits and the User has_many :edits.
So far it would look like:
# user.rb
class User < ActiveRecord::Base
has_many :edits
has_many :documents
end
# document.rb
class Document < ActiveRecord::Base
belongs_to :user
has_many :edits
end
# edit.rb
class Edit < ActiveRecord::Base
belongs_to :user
belongs_to :document
end
When I create a Document through a User, the association between the User and Document are fine in both directions (user.documents and document.user)
Now when I want to create an Edit, the edit should be against a Document but should also be associated with the user who generated the edit (edit.user).
When I'm building this in my RSpec tests I'm struggling to get the associations correct using the "standard" association methods. If I do #user.edits.build({...}) it will associate the user in the returned Edit object, but not the Document. Likewise when I do #document.edits.build({...}) it will associate the Document but not the User.
I supposed I could expose the user_id and post_id in the attr_accessible declaration but won't this but I fear this is not a best way of doing this. I have no real reason to fear other than the attributes are now accessible through mass assignment (from what I understand).
Am I going about this the wrong way or is there a better way to create and test all the associations?
class User < ActiveRecord::Base
has_many :edits, :through => :documents
has_many :documents
end