Clifton Labrum
Clifton Labrum

Reputation: 14068

DRY Use of Models in Ruby on Rails

I have the following helper method that I'm using to upload some records to Dropbox. For each of the three models (logbooks, aircraft, and approaches), I'm doing the exact same thing. I'd like to make this more DRY and only have the code once, but I don't understand how to reference a model in an abstracted way.

Any recommendations?

#------------------------------------------------------------
# Upload entries to Dropbox
#------------------------------------------------------------
def upload_items(items, folder, client)

  # Go through each item and upload it to Dropbox
  items.each do |item|

    if folder == 'logbook'
      # Get the file from the database to upload
      @logbook = current_user.logbooks.find_by_sync_id(item)
      # Upload it
      uploaded_file = client.put_file("/logbook/#{item}.json",@logbook.to_json, overwrite = true)
      # Reset the updated_flag in the database
      @logbook.update_attributes(updated_flag: 0)

    elsif folder == 'aircraft'
      # Get the file from the database to upload
      @aircraft = current_user.aircrafts.find_by_sync_id(item)
      # Upload it
      uploaded_file = client.put_file("/aircraft/#{item}.json",@aircraft.to_json, overwrite = true)
      # Reset the updated_flag in the database
      @aircraft.update_attributes(updated_flag: 0)

    elsif folder == 'approaches'
      # Get the file from the database to upload
      @approach = current_user.approaches.find_by_sync_id(item)
      # Upload it
      uploaded_file = client.put_file("/approaches/#{item}.json",@approach.to_json, overwrite = true)
      # Reset the updated_flag in the database
      @approach.update_attributes(updated_flag: 0)

    end
  end
end

Ruby 1.9.3, Rails 3.2.8

Upvotes: 0

Views: 137

Answers (3)

Hauleth
Hauleth

Reputation: 23566

I would write this that way:

class DropboxUploader
  attr_reader :folder, :client

  def initializer(folder, client)
    @folder = folder.to_sym
    @client = client
  end

  def upload(items)
    items.each { |item| update item }
  end

  def resource_name
    folder.to_s.pluralize.to_sym
  end

  def file_path
    "/#{folder}/#{item}.json"
  end

  private
  def find_resource_for(item)
    current_user.public_send(resource_name).find_by_sync_id(item)
  end

  def update(item)
    resource = find_resource_for item
    client.put_file(file_path, @aircraft.to_json, true)
    resource.update_attributes(updated_flag: 0)
  end
end

Not only DRY but more objective also (and easier to test).

EDIT: Usage goes as follows:

uploader = DropboxUploader.new(:aircraft, @client)
uploader.upload(@items)

Upvotes: 1

Daniel Evans
Daniel Evans

Reputation: 6808

This will do the job.

The critical part below is current_user.public_send(folder.to_sym) which takes the folder name and converts it to a message to send to the current_user.

#------------------------------------------------------------
# Upload entries to Dropbox
#------------------------------------------------------------
def upload_items(items, folder, client)

  # Go through each item and upload it to Dropbox
  items.each do |item|
    # Get the file from the database to upload
    resource = current_user.public_send(folder.pluralize.to_sym).find_by_sync_id(item)
    # Upload it
    uploaded_file = client.put_file("/#{folder}/#{item}.json",resource.to_json, overwrite = true)
    # Reset the updated_flag in the database
    resource.update_attributes(updated_flag: 0)
  end
end

Upvotes: 1

SG 86
SG 86

Reputation: 7078

This should be the direction:

Your Controller:

#------------------------------------------------------------
# Upload entries to Dropbox
#------------------------------------------------------------
def upload_items(items, folder, client)

  # Go through each item and upload it to Dropbox
  items.each do |item|
   upload_to_dropbox(items, folder, client)
  end
end

ApplicationController:

def upload_to_dropbox(item, folder, client)
  # Get the file from the database to upload
  @model = current_user.send(folder).find_by_sync_id(item)
  # Upload it
  uploaded_file = client.put_file("/aircraft/#{item}.json",@model.to_json, overwrite = true)
  # Reset the updated_flag in the database
  @model.update_attributes(updated_flag: 0)
end

Upvotes: 0

Related Questions