Reputation: 16989
I'm looking to implement a Status system like such:
# Group examples: user, post, comment
class StatusGroup < ActiveRecord::Base
has_many :status_group_options
has_many :status_options, -> { uniq }, through: :status_group_options
end
# Option examples: active, open, closed, banned, completed, deleted
class StatusOption < ActiveRecord::Base
has_many :status_group_options
has_many :status_groups, -> { uniq }, through: :status_group_options
end
# This would be to handle which groups have access to which options.
# For example, the user group wouldn't have access to the
# [open, closed, completed] options but would have access
# to the [active, banned, completed].
# StatusGroupOption also has a column labelled as admin to determine
# which statuses only admins can see.
class StatusGroupOption < ActiveRecord::Base
belongs_to :status_group
belongs_to :status_option
has_many :users
end
The user
, post
, and comment
table would then have a link to status_group_option_id
.
My problem is, I don't think I have the correct set up. It seems overly difficult to search for all users that are either in the open option or banned option. Additionally, it's difficult to search (using scopes) these tables for, say, the "deleted" option for "user" group ONLY.
Is this the correct approach? Am I over complicating things? I'm following this guide.
Upvotes: 0
Views: 44
Reputation: 1540
I would suggest looking into Enum
since you're using Rails 4. This will hopefully simplify a lot of confusion. Instead of creating separate models, what you could do is just implement the use of enum
into each of your models, that way each model has its own set of statuses.
Like so:
class User < ActiveRecord::Base
enum :status => [:active, :banned, :completed]
end
class Post < ActiveRecord::Base
enum :status => [:open, :closed, :deleted]
end
class Comment < ActiveRecord::Base
enum :status => [:open, :closed, :deleted, :flagged] # <= I threw "flagged" in there to show some variance
end
Basically enum
refers to an integer-based column in your table (in this case, I used :status
to represent the status
column in your db). The array here enumerates the different elements inside it ([:active, :banned, :completed]
, etc) by its index (0, 1, 2).
If you wanted to save a user with the status of active
, you could do this in your controller:
class UsersController < ApplicationController
def update
@user = User.find(params[:id])
@user.active! #=> updates the user's status as 0, since it was the first element in our enum array.
# here's another example, say if you wanted to update the user's status to "banned"
@user.banned! #=> updates the user's status as 2 in the database, since it was the third element in our array
end
end
So in your database you will see the integer value, but let's say you want to display the actual text of the status in your view:
show.html.erb
<!-- Instead of displaying the integer that's in your status column, it will display the text automagically of whatever status is set on that record -->
<%= @user.status %>
<!-- You can even do super convenient conditionals! Thanks, Rails! -->
<% if @user.active? %>
This user is active!
<% elsif @user.banned? %>
This user was banned!
<% end %>
So in a nutshell, I would say it would be better to create your "status options" within each respective model and define your "status options" using the enum
feature provided in Rails 4.
More about that here: http://edgeapi.rubyonrails.org/classes/ActiveRecord/Enum.html
You will most likely have to add these "status" columns to each table that would need it:
rails g migration add_status_column_to_users status:integer
rails g migration add_status_column_to_posts status:integer
rails g migration add_status_column_to_comments status:integer
rake db:migrate
Hope this helps! I usually build my Rails apps using enum
when I want to have models that need statuses (active, inactive) and roles (like admin, normal_user, etc). Let me know if you need any better clarification. I'm here to help!
Upvotes: 1