Skip to content

Commit

Permalink
Added update_or_create method (#4)
Browse files Browse the repository at this point in the history
* Added update_or_create method

This new method allows us to use multiple keys to identify records, it replaces the implementation of `.refresh`.

Fixes #2

* Fixed readme examples

* bump version to 1.0

* Send log messages to $stderr instead of stdout
  • Loading branch information
jamesbowles committed Jul 28, 2017
1 parent b61840c commit 09e0411
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 18 deletions.
13 changes: 10 additions & 3 deletions README.md
Expand Up @@ -37,9 +37,16 @@ Add this line to your application's deploy.rb file:
The below example ensures that there are 3 users existing in the database after running the 'rake reference_data:load'

### db/reference/000_users.rb
Easy::ReferenceData.refresh User, :system_code, 'nigel', name: 'Nigel Ramsay', email: 'nigel.ramsay@mailinator.com'
Easy::ReferenceData.refresh User, :system_code, 'fred', name: 'Fred Schmitt', email: 'fred.schmitt@mailinator.com'
Easy::ReferenceData.refresh User, :system_code, 'bert', name: 'Bert Symthe', email: 'bert.smythe@mailinator.com'
Easy::ReferenceData.update_or_create User, {system_code: 'nigel', name: 'Nigel Ramsay', email: 'nigel.ramsay@mailinator.com'}, keys: [:system_code]
Easy::ReferenceData.update_or_create User, {system_code: 'fred', name: 'Fred Schmitt', email: 'fred.schmitt@mailinator.com'}, keys: [:system_code]
Easy::ReferenceData.update_or_create User, {system_code: 'bert', name: 'Bert Symthe', email: 'bert.smythe@mailinator.com'}, keys: [:system_code]

Multiple keys can be used to identify records that would otherwise not have a unique attribute

### db/reference/000_prices.rb
Easy::ReferenceData.update_or_create Price, {product_id: 1, type: "Price::RetailPrice", price: 5}, keys: [:product_id, :type]
Easy::ReferenceData.update_or_create Price, {product_id: 1, type: "Price::CostPrice", price: 4}, keys: [:product_id, :type]
Easy::ReferenceData.update_or_create Price, {product_id: 2, type: "Price::RetailPrice", price: 5}, keys: [:product_id, :type]

## Contributing

Expand Down
26 changes: 13 additions & 13 deletions lib/easy/reference_data/refresh.rb
@@ -1,31 +1,31 @@
require 'active_support'

module Easy
module ReferenceData
def self.refresh(clazz, unique_attribute_symbol, unique_attribute_value, attributes)
record = clazz.where(unique_attribute_symbol => unique_attribute_value).first
self.update_or_create(clazz, attributes.merge(unique_attribute_symbol => unique_attribute_value), keys: [unique_attribute_symbol])
end

if record.nil?
record = clazz.new
record.send "#{unique_attribute_symbol}=", unique_attribute_value
end
def self.update_or_create(clazz, attributes, options)
unique_attribute_keys = options.fetch(:keys)

attributes.each_pair do |key, value|
record.send "#{key}=", value
end
record = clazz.where(attributes.slice(*unique_attribute_keys)).first_or_initialize

if record.new_record?
puts "..creating #{clazz}(#{unique_attribute_value})"
elsif record.changed?
puts "..updating #{clazz}(#{unique_attribute_value})"
$stderr.puts "..creating #{clazz}(#{attributes.slice(*unique_attribute_keys)})"
else
$stderr.puts "..updating #{clazz}(#{attributes.slice(*unique_attribute_keys)})"
end

begin
record.save!
record.update_attributes!(attributes)
rescue
puts "Save failed for #{record.class}[#{unique_attribute_symbol}: #{unique_attribute_value}] with attributes #{attributes.inspect}"
$stderr.puts "Save failed for #{record.class} with attributes #{attributes.inspect}"
raise
end

record
end

end
end
4 changes: 2 additions & 2 deletions lib/easy/reference_data/version.rb
@@ -1,5 +1,5 @@
module Easy
module ReferenceData
VERSION = "0.1.2"
VERSION = "1.0.0"
end
end
end
38 changes: 38 additions & 0 deletions spec/easy/reference_data/refresh_spec.rb
Expand Up @@ -3,6 +3,44 @@

RSpec.describe Easy::ReferenceData do

describe ".update_or_create" do
context "with a single unique attribute" do
context "and an existing record" do

it "does not change the record" do
user = User.create(system_code: 1)

expect{ Easy::ReferenceData.update_or_create(User, {system_code: 1}, keys: [:system_code])}.not_to change{ User.count }
end

context "with additional attribues" do
it "updates the existing record" do
user = User.create(system_code: 1, name: "Jo")

expect{ Easy::ReferenceData.update_or_create(User, {system_code: 1, name: "Jane"}, keys: [:system_code])}.to change{ user.reload.name }.to "Jane"
end
end
end

context "and no existing record" do
it "creates a new record" do
expect{ Easy::ReferenceData.update_or_create(User, {system_code: 1}, keys: [:system_code])}.to change{ User.count }
end
end

end

context "with multiple attributes" do
it "updates the matching record" do
jo_smith = User.create(system_code: 1, name: "Jo", email: "jo.smith@example.com")
jo_brown = User.create(system_code: 1, name: "Jo", email: "jo.brown@example.com")

expect{ Easy::ReferenceData.update_or_create(User, {name: "Jo", email: "jo.brown@example.com", system_code: 2}, keys: [:name, :email])}.to change{ jo_brown.reload.system_code }.to 2
end

end
end

describe ".refresh" do

context "with a unique attribue" do
Expand Down

0 comments on commit 09e0411

Please sign in to comment.