简体   繁体   中英

Rails 5 Model.where(user_id) - Two levels up

Terribly worded, but I'm confusing it.

I have a User model who has_many Clients and has_many statements, through: :clients and then statements which belongs_to clients and belongs to user

In Console I can do all the queries I want. User.statements User.client.first.statements etc - What I'm struggling on is Controller restrictions

For now it's simple - A user should only be able to see Clients and Statements in which they own.

For Clients I did Client Controller

def index
    @clients = Client.where(user_id: current_user.id)
end

Which seems to work perfectly. Client has a field for user_id

I'm kind of stuck on how to emulate this for Statements. Statements do -not- have a user_id field. I'm not quite sure I want them too since in the very-soon-future I want clients to belongs_to_many :users and Statements to not be bound.

Statement Controller

  def index
    @clients = Client.where(user_id: current_user.id)
    @statements = Statement.where(params[:client_id])
  end

I'm just genuinely not sure what to put - I know the params[:client_id] doesn't make sense, but what is the proper way to fulfill this? Am I going about it an unsecure way?

Client Model

class Client < ApplicationRecord
    has_many :statements
    has_many :client_notes, inverse_of: :client
    belongs_to :user
    validates :name, presence: true
    validates :status, presence: true
    accepts_nested_attributes_for :client_notes, reject_if: :all_blank, allow_destroy: true
end

Statement Model

class Statement < ApplicationRecord
    belongs_to :client
    belongs_to :user
    validates :name, presence: true
    validates :statement_type, presence: true
    validates :client_id, presence: true
    validates :start_date, presence: true
    validates :end_date, presence: true
end

User Model

class User < ApplicationRecord

  has_many :clients
  has_many :statements, through: :clients
end

Based on the reply provided below I am using

  def index
    if params[:client][:user_id] == @current_user.id
      @clients = Client.includes(:statements).where(user_id: params[:client][:user_id])
      @statements = @clients.statements
    else
      return 'error'
    end
  end

Unsure if this logic is proper

Use includes to avoid [N+1] queries.

And regarding "A user should only be able to see Clients and Statements in which they own" .

if params[:client][:user_id] == @current_user.id
  @clients = Client.includes(:statements).where(user_id: params[:client][:user_id])
  # do more
else
  # Type your error message
end

Additionally, you might need to use strong params and scope .

The best way to do it is using includes:

@clients = Client.where(user_id: current_user.id)
@statements = Statement.includes(clients: :users}).where('users.id = ?', current_user.id)

You can take a look in here: https://apidock.com/rails/ActiveRecord/QueryMethods/includes

In this case, thanks to the reminder that current_user is a helper from Devise, and the relational structure I showed, it was actually just as simple as

def index
    @statements = current_user.statements
end

resolved my issue.

Due to the [N+1] Queries issue that @BigB has brought to my attention, while this method works, I wouldn't suggest it for a sizable transaction.

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