0
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.

3
  • I don't understand what you mean by "doing it in the controller", but you can just add an instance method or a scope called current_interaction to your Application model. Commented Oct 20, 2015 at 14:25
  • Ahhh you beat me to it by one minute! Yeah I think that would work, thanks! Commented Oct 20, 2015 at 14:27
  • I approved the edit you suggested, but other commenters pointed out that it would be better as its own answer, or as an edit to your question pointing out that it's the solution you arrived at (not sure which is preferred), so I reverted my answer back to the previous version. Sorry for the confusion, but glad you got it working! Commented Oct 20, 2015 at 18:36

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.