1

I am looking for a better method with designing some Rails views that require a lot of controller data shared across various models. It is often that i come across a scenario where i need to combine an association with various other models. Think of this scenario (this comes from a game):

  1. A city has many buildings (user has many buildings through city_buildings)
  2. Now, each building can be upgraded based on requirements. Let's say that in order to build a fire station, you first need to already have a well.
  3. My application shows the currently built buildings. It iterates through @city.buildings, along with their requirements, if they cannot be built.

Now, my problem is handling this data properly in my controller/view. I always try to use as fewer code inside my views as possible and try to use instance variables mainly there. Each building has different requirements that originate from the association building.requirements. Part of my view depends on this requirements, and i therefore have to have checks like this all over my view :

<% if building.fulfil_requirements?(city) %>

In the past, I've tried using SQL joins in order to create instance variables that have more information about an association, based on other models as well, but i find this technique quite messy. There are some occasions where the need to calculate something inside a foreach loop has me running a model method inside a view, which is something i really really not like.

So, I am wondering whether there's a better solution for combining multiple models behavior inside my views, without having to resort to adding logic inside my views.

Spyros
  • 46,820
  • 25
  • 86
  • 129

1 Answers1

0

So you're looking to only show buildings with specific requirements?


Modularity

There's a convention in Rails (and general MVC) called fat model skinny controller, which means you should include as much conditional logic in your models as possible, referencing the relevant methods / functions as required

I would recommend incorporating your conditional logic into your models, allowing you to simply call the data you require from your controller (& output in the view), like this:


Model

Uses ActiveRecord Association Extensions, but could use a scope

#app/models/city.rb
Class City < ActiveRecord::Base
    has_many :buildings do 
        def fulfil_requirements
            where([requirements])
        end
    end
end

This uses a simple where call to pull data based on specific requirements. This data will be passed to any variable you wish


Controller

#app/controllers/cities_controller.rb
def show
    @city = City.find(params[:id])
    @buildings = @city.buildings.fulfil_requirements
end

By receiving conditional data, you just have to assign the populate the @buildings variable with the data, which you can then pass to the view


View

#app/views/cities/show.html.erb
<% @buildings.each do |building| %>
    your code here
<% end %>

By passing only the required data to your view, you can then manipulate only that data (don't have to worry about conditions). This makes the view much clearer & the system more modular

Community
  • 1
  • 1
Richard Peck
  • 76,116
  • 9
  • 93
  • 147
  • Hey Rich Peck, thank you for the answer. This is not exactly what i want though. I want to show all buildings, including those that have requirements or not. This is why i used joins in the past. I've always been having issues when such scenarios rise, because i haven't found a nice way of including this extra model information without joins or dynamically adding the evaluation in the views. – Spyros Mar 01 '14 at 18:22
  • If that's the case, you'd be best using logic in the view then, surely? – Richard Peck Mar 01 '14 at 18:23
  • Yes, it looks to me like this is the only way. I just wanted to make sure i am not missing anything, because if i could remove model code from my views, i would really be in for that. – Spyros Mar 02 '14 at 04:47