简体   繁体   中英

Rails many-to-many setup

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.

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!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM