Tammy Pop Tammy Pop - 3 months ago 5
Ruby Question

assigning and reusing variables in Rails - design pattern

I've been using the same pattern for returning json code (see example below). I'm getting a collection of photos and storing it in the variable. If tag param is present, I'm getting a more specific collection and reassigning it to the same variable. Then returning it as json. What would be a better design pattern to achieve the same thing?

photos = collection_of_photos
if params[:tag]
photos = photos.find_all {|photo| some condition}
render json: photos


If the photos are ActiveRecord objects you should use a scope to generate the appropriate query for the exact data you need. Otherwise, Rails will load all of the photos instead of the subset you need. Assuming your photos records have a single tag attribute, you can do something like the following:

class Photo < ApplicationRecord
  scope :with_tag, (tag) -> { where(tag: tag) }

In your controller you'd only need the call that scope since ActiveRecord scopes return an #all scope if no parameters are provided:

render json: Photo.with_tag(params[:tag])

# Equivalent when params[:tag] is nil
render json: Photo.all

Now say you're not dealing with ActiveRecord objects. Say you have an array of hashes:

photos = [{ name: '1.jpg', tag: 'flower'}, ... ]

You can create a helper method to perform the filtering:

class PhotosController < ApplicationController
  def index
    photos = [{ name: '1.jpg', tag: 'flower'}, ... ]
    render json: select_photos_by_tag(photos, params[:tag])


  def select_photos_by_tag(photos, tag)
    if tag
      photos.select { |photo| photo[:tag] == tag }