Bradley Oesch
Bradley Oesch

Reputation: 763

How to limit what data I pass in from the controller in Ruby on Rails

class Board < ActiveRecord::Base
  has_many :applications, dependent: :destroy
end

class Application < ActiveRecord::Base
  belongs_to :board
  validates_presence_of :board
  has_many :interactions, dependent: :destroy
end

class Interaction < ActiveRecord::Base
  belongs_to :application
  validates_presence_of :application
end

Given the above ActiveRecords, in the show method of boards_controller, I can call @boards.applications, and even though I don't explicitly call application.interactions I still have access to the interactions in the view. However, for this particular view, I only need one interaction, which is gathered through some logic having to do with nil checks and sorting.

I would rather do this logic in the controller and only pass that one interaction in instead of all the extras for every application, but currently it's passing all of them and I can't explicitly add an application.current_interaction in the controller because it's an unknown attribute.

How can I set one interaction for each application, and what is the proper way to do it in Ruby on Rails?

Here's what I ended up doing:

The application model should look like this:

class Application < ActiveRecord::Base
  belongs_to :board
  validates_presence_of :board
  has_many :interactions, dependent: :destroy

  def current_interaction
    #logic here
    return interaction
  end
end

Then it can be called in the view with <%= application.current_interaction %>, there shouldn't have to be any changes to the controller at all.

Upvotes: 0

Views: 145

Answers (2)

elements
elements

Reputation: 1057

I believe lazy-loading is the default behavior when retrieving the interactions from an application, so they shouldn't get fetched from the db until you call application.interactions. But, you say that you don't explicitly call application.interactions, so how are you seeing that they're accessible?

You can wrap that "nil checks and sorting" logic in a current_interaction method on Application, and the interactions shouldn't be loaded unless you explicitly call them.

Upvotes: 1

jrochkind
jrochkind

Reputation: 23317

If the model Board has a relationship to applications, then anything with a Board object in @board can call @board.applications to get all the applications associated with that board. There is no way to prevent this.

But just because it can call that to get all applications doesn't mean it has to. Don't look at @board.applications unless you want all the applications for that board.

If instead:

However, for this particular view, I only need one interaction, which is gathered through some logic having to do with nil checks and sorting.

I would rather do this logic in the controller and only pass that one interaction in instead of all the extras for every application,

No problem! Just do that. You just won't pass it to the view as an attribute of the @board, it'll be it's own thing.

 # in controller
 @current_interaction = find_current_interaction_for(@board)

 # Or, instead, use template-parameters instead of using ivars
 render "some_template", :locals => {:board => @board, :current_interaction => find_current_interaction_for_board(@board)}

You can't remove "access to the interactions in the view" -- so long as the relationship is defined in the model, they are "accessible". But if no code accesses @board.interactions, they won't neccesarily be actually loaded, until accessed.

But if all the interactions aren't what you want in this view but only a certain one, and you want to calculate that certain one in the controller -- just calculate it in the controller and pass it in as a separate param. You were getting stuck thinking the view needed to the get the current_interaction from the Board model somehow, but it doesn't. If it makes sense to calculate it in the controller, then the controller has to pass it to the view separately. @board.applications will always be all the applications for the board, if you don't want all the applications don't look at that property, put the thing you want somewhere else.

Upvotes: 0

Related Questions