nihaopay-ruby 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE +22 -0
- data/README.md +344 -0
- data/lib/nihaopay-ruby.rb +29 -0
- data/lib/nihaopay/configure.rb +14 -0
- data/lib/nihaopay/credit_card.rb +27 -0
- data/lib/nihaopay/errors.rb +6 -0
- data/lib/nihaopay/merchant.rb +47 -0
- data/lib/nihaopay/mixins/api.rb +41 -0
- data/lib/nihaopay/mixins/queryable.rb +41 -0
- data/lib/nihaopay/query.rb +61 -0
- data/lib/nihaopay/secure_pay/ali_pay.rb +11 -0
- data/lib/nihaopay/secure_pay/base.rb +48 -0
- data/lib/nihaopay/secure_pay/union_pay.rb +11 -0
- data/lib/nihaopay/secure_pay/we_chat_pay.rb +11 -0
- data/lib/nihaopay/transactions/authorize.rb +37 -0
- data/lib/nihaopay/transactions/base.rb +78 -0
- data/lib/nihaopay/transactions/cancel.rb +28 -0
- data/lib/nihaopay/transactions/capture.rb +29 -0
- data/lib/nihaopay/transactions/purchase.rb +11 -0
- data/lib/nihaopay/transactions/refund.rb +31 -0
- data/lib/nihaopay/transactions/release.rb +28 -0
- data/lib/nihaopay/util/hash_util.rb +30 -0
- data/lib/nihaopay/version.rb +3 -0
- data/spec/credit_card_spec.rb +56 -0
- data/spec/merchant_spec.rb +142 -0
- data/spec/mixins/api_spec.rb +81 -0
- data/spec/mixins/queryable_spec.rb +95 -0
- data/spec/query_spec.rb +129 -0
- data/spec/secure_pay/ali_pay_spec.rb +112 -0
- data/spec/secure_pay/union_pay_spec.rb +13 -0
- data/spec/secure_pay/we_chat_pay_spec.rb +13 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/transactions/authorize_spec.rb +115 -0
- data/spec/transactions/base_spec.rb +184 -0
- data/spec/transactions/cancel_spec.rb +83 -0
- data/spec/transactions/capture_spec.rb +85 -0
- data/spec/transactions/purchase_spec.rb +7 -0
- data/spec/transactions/refund_spec.rb +98 -0
- data/spec/transactions/release_spec.rb +83 -0
- data/spec/util/hash_util_spec.rb +22 -0
- metadata +187 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8766c2c6e2a61b1ac8c0cd497e8fe871cc0d34c6
|
4
|
+
data.tar.gz: 08aaa9b825ad38032cc436061e09b2d0d3a476db
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 980bd29de13afa1d13b0664e5a52f1e2ad6df160900031a402691b832780e2ea8abf59f03fd78dd9828893411f7ffdf3befc15dc72a7408a0ab8d2f27faf36e9
|
7
|
+
data.tar.gz: a818aa490245aa0f9a71ff32c9f667cc14017380d077ccb66cdb9878da19a35129a22293243545c683663a3c8f805e70f35ae3467582fbcb3f4c191549b8dfc3
|
data/CHANGELOG.md
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2016 KK VESPER
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
|
22
|
+
NihaoPay is trademark of Aurfy Inc. Aurfy Inc does not provide or endorse this library.
|
data/README.md
ADDED
@@ -0,0 +1,344 @@
|
|
1
|
+
# Nihaopay Ruby
|
2
|
+
|
3
|
+
[![Build Status](https://travis-ci.org/kkvesper/nihaopay-ruby.svg?branch=master)](https://travis-ci.org/kkvesper/nihaopay-ruby)
|
4
|
+
|
5
|
+
Nihaopay Ruby is a Ruby wrapper for using the [Nihaopay](https://www.nihaopay.com) payment gateway API.
|
6
|
+
|
7
|
+
This library is provided by [KK VESPER](https://www.kkvesper.jp/) and is not affiliated
|
8
|
+
with or supported by [Aurfy Inc](https://www.nihaopay.com), makers of Nihaopay.
|
9
|
+
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
Add the following to your Gemfile:
|
14
|
+
|
15
|
+
`gem 'nihaopay-ruby'`
|
16
|
+
|
17
|
+
and run `bundle install`
|
18
|
+
|
19
|
+
#### Configuration
|
20
|
+
|
21
|
+
Add a file *config/initializers/nihaopay.rb*.
|
22
|
+
|
23
|
+
``` ruby
|
24
|
+
Nihaopay.configure do |nihaopay|
|
25
|
+
nihaopay.test_mode = true
|
26
|
+
nihaopay.token = <your-merchant-token>
|
27
|
+
nihaopay.currency = 'USD'
|
28
|
+
end
|
29
|
+
```
|
30
|
+
|
31
|
+
The default value for `test_mode` is `false`. Default `currency` is `'USD'`.
|
32
|
+
|
33
|
+
|
34
|
+
## Initiate a SecurePay transaction
|
35
|
+
|
36
|
+
#### UnionPay
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
options = { reference: '3461fcc31aec471780ad1a4dc6111947',
|
40
|
+
ipn_url: 'http://website.com/ipn',
|
41
|
+
callback_url: 'http://website.com/callback' }
|
42
|
+
response = Nihaopay::SecurePay::UnionPay.start(amount, currency, options)
|
43
|
+
render inline: "<%= response.body %>"
|
44
|
+
```
|
45
|
+
|
46
|
+
`amount` should be an integer of the minor unit in the currency, e.g. $10.50 in USD would be 1050.
|
47
|
+
|
48
|
+
`currency` can be `'USD'` and `'JPY'`.
|
49
|
+
|
50
|
+
**Options:**
|
51
|
+
|
52
|
+
- `reference` is an alphanumeric string up to 30 characters that must be unique to each of your transactions.
|
53
|
+
- `ipn_url` is Instant Payment Notification URL called by the API to update you on the transaction information.
|
54
|
+
- `callback_url` is the URL the browser will be redirected to upon completing the transaction.
|
55
|
+
- `description` (optional)
|
56
|
+
- `note` (optional)
|
57
|
+
- `terminal` (optional) specifies whether payment is submitted on desktop (*ONLINE*) or mobile (*WAP*). Currently, acceptable values are *ONLINE* and *WAP*. Please note *WAP* for WeChat Pay is only available in live environment.
|
58
|
+
- `timeout` (optional) specifies amount of minutes card holders have before payment page times out. Once the page times out without a successful payment, the transaction is automatically cancelled. Acceptable values are *1 - 1440*.
|
59
|
+
|
60
|
+
Due to the nature of redirects and users being able to close their browsers before the redirect can happen, an instant payment notification (IPN) URL is used to provide transaction data.
|
61
|
+
|
62
|
+
Whenever possible, transaction data should be recorded from the IPN URL instead of the callback URL.
|
63
|
+
|
64
|
+
Sample Credit Card details for UnionPay are:
|
65
|
+
|
66
|
+
- Number: 6221 5588 1234 0000
|
67
|
+
- Expiry year: 17
|
68
|
+
- Expiry month: 11
|
69
|
+
- Last 3 digits: 123
|
70
|
+
- Phone: 1-355-253-5506
|
71
|
+
- Sms verification: 111111
|
72
|
+
|
73
|
+
**Override global token**
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
merchant = Nihaopay::Merchant.new(token)
|
77
|
+
response = merchant.union_pay(amount, currency, options)
|
78
|
+
```
|
79
|
+
|
80
|
+
#### AliPay
|
81
|
+
|
82
|
+
You can use the same `options` from *UnionPay* for *AliPay* transactions.
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
response = Nihaopay::SecurePay::AliPay.start(amount, currency, options)
|
86
|
+
```
|
87
|
+
|
88
|
+
Sample account details for AliPay are:
|
89
|
+
- Number: 13122443313
|
90
|
+
- Login password: 111111
|
91
|
+
- Payment password: 111111
|
92
|
+
|
93
|
+
**Override global token**
|
94
|
+
|
95
|
+
```ruby
|
96
|
+
merchant = Nihaopay::Merchant.new(token)
|
97
|
+
response = merchant.ali_pay(amount, currency, options)
|
98
|
+
```
|
99
|
+
|
100
|
+
#### WeChatPay
|
101
|
+
|
102
|
+
You can use the same `options` from *UnionPay* for *WeChatPay* transactions.
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
response = Nihaopay::SecurePay::WeChatPay.start(amount, currency, options)
|
106
|
+
```
|
107
|
+
|
108
|
+
For WeChatPay, you will see a QR code on the vendor payment page. Scan the code from WeChat mobile app and complete the payment. It will automatically redirect to Callback URL upon payment completion.
|
109
|
+
|
110
|
+
**Override global token**
|
111
|
+
|
112
|
+
```ruby
|
113
|
+
merchant = Nihaopay::Merchant.new(token)
|
114
|
+
response = merchant.wechat_pay(amount, currency, options)
|
115
|
+
```
|
116
|
+
|
117
|
+
|
118
|
+
## ExpressPay
|
119
|
+
|
120
|
+
#### Authorize transaction on ExpressPay
|
121
|
+
|
122
|
+
You need the credit card details for initiating the transaction. You can build the credit card object as below:
|
123
|
+
|
124
|
+
``` ruby
|
125
|
+
credit_card = Nihaopay::CreditCard.new(
|
126
|
+
number: '6221558812340000',
|
127
|
+
expiry_year: 2017,
|
128
|
+
expiry_month: 11,
|
129
|
+
cvv: '123')
|
130
|
+
```
|
131
|
+
|
132
|
+
Acceptable values for `expiry_month` are `01` through `12`.
|
133
|
+
|
134
|
+
Now initiate the transaction using above credit card.
|
135
|
+
|
136
|
+
``` ruby
|
137
|
+
express_pay = Nihaopay::Transactions::Authorize.start(amount, credit_card)
|
138
|
+
```
|
139
|
+
|
140
|
+
This returns an instance of `Nihaopay::Transactions::ExpressPay` on which you can access following methods:
|
141
|
+
|
142
|
+
``` ruby
|
143
|
+
express_pay.transaction_id # => "20160714132438002485"
|
144
|
+
express_pay.status # => "success"
|
145
|
+
express_pay.reference # => "3461fcc31aec471780ad1a4dc6111947"
|
146
|
+
express_pay.currency # => "JPY"
|
147
|
+
express_pay.amount # => 1000
|
148
|
+
express_pay.captured # => false
|
149
|
+
```
|
150
|
+
|
151
|
+
Other methods available are `note` and `time`.
|
152
|
+
|
153
|
+
#### Purchase transaction on ExpressPay
|
154
|
+
|
155
|
+
``` ruby
|
156
|
+
express_pay = Nihaopay::Transactions::Purchase.start(amount, credit_card)
|
157
|
+
```
|
158
|
+
|
159
|
+
This again returns an instance of `Nihaopay::Transactions::ExpressPay`.
|
160
|
+
|
161
|
+
#### Options for ExpressPay transactions
|
162
|
+
|
163
|
+
For `authorize` and `purchase`, you can pass `currency`, `description`, `note`, and `reference` as options.
|
164
|
+
|
165
|
+
``` ruby
|
166
|
+
express_pay = Nihaopay::Transactions::Authorize.start(amount, credit_card, { currency: 'USD',
|
167
|
+
description: 'Your order description',
|
168
|
+
note: 'Something to remember',
|
169
|
+
reference: 'A unique alphanumeric string' })
|
170
|
+
```
|
171
|
+
|
172
|
+
Acceptable currency codes are 'USD' and 'JPY'.
|
173
|
+
|
174
|
+
#### Capture a transaction
|
175
|
+
|
176
|
+
``` ruby
|
177
|
+
captured = express_pay.capture
|
178
|
+
captured.transaction_id # => "20160718111604002633"
|
179
|
+
captured.status # => "success"
|
180
|
+
captured.captured # => true
|
181
|
+
captured.capture_transaction_id # => "20160718111529002632" (id of the transaction that was captured)
|
182
|
+
```
|
183
|
+
|
184
|
+
If you want to capture a partial amount, you can do:
|
185
|
+
|
186
|
+
``` ruby
|
187
|
+
captured = express_pay.partial_capture(amount)
|
188
|
+
```
|
189
|
+
|
190
|
+
Authorizations not captured within 30 days are automatically released and cannot be captured.
|
191
|
+
|
192
|
+
#### Release a transaction
|
193
|
+
|
194
|
+
Release an uncaptured transaction.
|
195
|
+
|
196
|
+
``` ruby
|
197
|
+
released = express_pay.release
|
198
|
+
released.transaction_id # => "20160718111604002633"
|
199
|
+
released.status # => "success"
|
200
|
+
released.released # => true
|
201
|
+
released.release_transaction_id # => "20160718111529002632" (id of the transaction that was released)
|
202
|
+
```
|
203
|
+
|
204
|
+
#### Cancel a transaction
|
205
|
+
|
206
|
+
``` ruby
|
207
|
+
cancelled = express_pay.cancel
|
208
|
+
cancelled.transaction_id # => "20160718111604002633"
|
209
|
+
cancelled.status # => "success"
|
210
|
+
cancelled.cancelled # => true
|
211
|
+
cancelled.cancel_transaction_id # => "20160718111529002632" (id of the transaction that was cancelled)
|
212
|
+
```
|
213
|
+
|
214
|
+
Transactions can only be cancelled before the daily settlement deadline. Transactions cannot be cancelled if a partial or full refund on the transaction has already been issued.
|
215
|
+
|
216
|
+
|
217
|
+
## Working with transactions
|
218
|
+
|
219
|
+
#### List transactions
|
220
|
+
|
221
|
+
Only SecurePay, ExpressPay, and Captured transactions can be returned. For details on Released, Cancelled, and Refunded transactions, please navigate to the [TMS](https://tms.nihaopay.com). Transactions are returned with the most recent transactions appearing first.
|
222
|
+
|
223
|
+
``` ruby
|
224
|
+
transactions = Nihaopay::Transactions::Base.fetch
|
225
|
+
```
|
226
|
+
|
227
|
+
By default, only 10 transactions are returned at a time. This can be adjusted by calling `limit` before `fetch`. `limit` can range between 1 and 100.
|
228
|
+
|
229
|
+
``` ruby
|
230
|
+
transactions = Nihaopay::Transactions::Base.limit(5).fetch
|
231
|
+
```
|
232
|
+
|
233
|
+
To retrieve transactions that were processed after the specified time, you can all `after` with time in *yyyy-mm-ddThh:mm:ssZ* format.
|
234
|
+
|
235
|
+
``` ruby
|
236
|
+
transactions = Nihaopay::Transactions::Base.after('2016-06-01T01:00:00Z').fetch
|
237
|
+
```
|
238
|
+
|
239
|
+
Similarly, you can fetch the transactions that were processed before the specified time.
|
240
|
+
|
241
|
+
``` ruby
|
242
|
+
transactions = Nihaopay::Transactions::Base.before('2016-06-01T01:00:00Z').fetch
|
243
|
+
```
|
244
|
+
|
245
|
+
You can chain methods to use multiple options:
|
246
|
+
|
247
|
+
``` ruby
|
248
|
+
transactions = Nihaopay::Transactions::Base.before('2016-07-01T01:00:00Z')
|
249
|
+
.after('2016-06-01T01:00:00Z')
|
250
|
+
.limit(5).fetch
|
251
|
+
```
|
252
|
+
|
253
|
+
OR
|
254
|
+
|
255
|
+
you can pass the options to `fetch`:
|
256
|
+
|
257
|
+
``` ruby
|
258
|
+
transactions = Nihaopay::Transactions::Base.fetch(before: '2016-07-01T01:00:00Z',
|
259
|
+
after: '2016-06-01T01:00:00Z',
|
260
|
+
limit: 5)
|
261
|
+
```
|
262
|
+
|
263
|
+
#### Look up a transaction
|
264
|
+
|
265
|
+
Provide a unique transaction ID that was returned from a previous response in order to retrieve corresponding transaction’s details.
|
266
|
+
|
267
|
+
``` ruby
|
268
|
+
transaction = Nihaopay::Transactions::Base.find(transaction_id)
|
269
|
+
transaction.transaction_id # => "20160718111604002633"
|
270
|
+
transaction.type # => "charge"
|
271
|
+
transaction.status # => "success"
|
272
|
+
```
|
273
|
+
|
274
|
+
Possible values of `transaction.type` are *"charge"*, *"authorization"*, or *"capture"*. You can also access `amount`, `currency`, `time`, `reference`, and `note` on above `transaction` object.
|
275
|
+
|
276
|
+
Only SecurePay (UnionPay and AliPay), ExpressPay, and Captured transaction details can be found. For details on Released, Cancelled, and Refunded transactions, please navigate to the [TMS](https://tms.nihaopay.com)
|
277
|
+
|
278
|
+
#### Refund a transaction
|
279
|
+
|
280
|
+
Full refunds can only be created once per transaction.
|
281
|
+
|
282
|
+
``` ruby
|
283
|
+
refunded = express_pay.refund
|
284
|
+
refunded.transaction_id # => "20160718111604002633"
|
285
|
+
refunded.status # => "success"
|
286
|
+
refunded.refunded # => true
|
287
|
+
refunded.refund_transaction_id # => "20160718111529002632" (id of the transaction that was refunded)
|
288
|
+
```
|
289
|
+
|
290
|
+
You can pass a `reason` when refunding a transaction:
|
291
|
+
|
292
|
+
``` ruby
|
293
|
+
refunded = express_pay.refund(reason: 'Out of stock')
|
294
|
+
```
|
295
|
+
|
296
|
+
Partial refunds can be created multiple times up to the amount of the Transaction.
|
297
|
+
|
298
|
+
``` ruby
|
299
|
+
refunded = express_pay.partial_refund(amount)
|
300
|
+
refunded = express_pay.partial_refund(amount, reason: 'Cancellation fee')
|
301
|
+
```
|
302
|
+
|
303
|
+
#### Override global token
|
304
|
+
|
305
|
+
If you have multiple merchants configured to the Nihaopay payment gateway, they will have different tokens each. You can do transactions per merchant as below:
|
306
|
+
|
307
|
+
``` ruby
|
308
|
+
merchant_token = "6c4dc4828474fa73c5f438a9eb2fbf3092e44"
|
309
|
+
nihaopay_merchant = Nihaopay::Merchant.new(merchant_token)
|
310
|
+
express_pay = nihaopay_merchant.authorize(amount, credit_card)
|
311
|
+
```
|
312
|
+
|
313
|
+
OR
|
314
|
+
|
315
|
+
``` ruby
|
316
|
+
express_pay = nihaopay_merchant.authorize(amount, credit_card, options)
|
317
|
+
```
|
318
|
+
|
319
|
+
`options` may include `currency`, `description`, `reference`, and `note`.
|
320
|
+
|
321
|
+
Similarly, you can do other transactions directly on `Nihaopay::Merchant` object:
|
322
|
+
|
323
|
+
``` ruby
|
324
|
+
# capture
|
325
|
+
express_pay = nihaopay_merchant.capture(transaction_id, amount, currency)
|
326
|
+
|
327
|
+
# purchase
|
328
|
+
express_pay = nihaopay_merchant.purchase(amount, credit_card)
|
329
|
+
express_pay = nihaopay_merchant.purchase(amount, credit_card, options)
|
330
|
+
|
331
|
+
# release
|
332
|
+
express_pay = nihaopay_merchant.release(transaction_id)
|
333
|
+
|
334
|
+
#refund
|
335
|
+
express_pay = nihaopay_merchant.refund(transaction_id, amount, currency)
|
336
|
+
express_pay = nihaopay_merchant.refund(transaction_id, amount, currency, reason: 'Cancellation fee')
|
337
|
+
```
|
338
|
+
|
339
|
+
|
340
|
+
## License
|
341
|
+
|
342
|
+
This library is provided by [KK VESPER](https://www.kkvesper.jp/) under the MIT License. Refer to LICENSE for details.
|
343
|
+
|
344
|
+
NihaoPay is trademark of [Aurfy Inc](https://www.nihaopay.com). Aurfy Inc does not provide, support, or endorse this library.
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
|
3
|
+
require 'nihaopay/util/hash_util'
|
4
|
+
|
5
|
+
require 'nihaopay/mixins/api'
|
6
|
+
require 'nihaopay/mixins/queryable'
|
7
|
+
|
8
|
+
require 'nihaopay/configure'
|
9
|
+
require 'nihaopay/credit_card'
|
10
|
+
require 'nihaopay/errors'
|
11
|
+
require 'nihaopay/merchant'
|
12
|
+
require 'nihaopay/query'
|
13
|
+
require 'nihaopay/version'
|
14
|
+
|
15
|
+
require 'nihaopay/secure_pay/base'
|
16
|
+
require 'nihaopay/secure_pay/ali_pay'
|
17
|
+
require 'nihaopay/secure_pay/union_pay'
|
18
|
+
require 'nihaopay/secure_pay/we_chat_pay'
|
19
|
+
|
20
|
+
require 'nihaopay/transactions/base'
|
21
|
+
require 'nihaopay/transactions/authorize'
|
22
|
+
require 'nihaopay/transactions/cancel'
|
23
|
+
require 'nihaopay/transactions/capture'
|
24
|
+
require 'nihaopay/transactions/purchase'
|
25
|
+
require 'nihaopay/transactions/refund'
|
26
|
+
require 'nihaopay/transactions/release'
|
27
|
+
|
28
|
+
module Nihaopay
|
29
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Nihaopay
|
2
|
+
class CreditCard
|
3
|
+
ATTRIBUTES = %i(number expiry_year expiry_month cvv).freeze
|
4
|
+
|
5
|
+
attr_accessor(*ATTRIBUTES)
|
6
|
+
|
7
|
+
def initialize(attributes = {})
|
8
|
+
attributes = Nihaopay::HashUtil.symbolize_keys(attributes)
|
9
|
+
assign_attributes(attributes)
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_params_hash
|
13
|
+
{ card_number: number,
|
14
|
+
card_exp_year: expiry_year,
|
15
|
+
card_exp_month: expiry_month,
|
16
|
+
card_cvv: cvv }
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def assign_attributes(attributes)
|
22
|
+
ATTRIBUTES.each do |attribute|
|
23
|
+
send("#{attribute}=", attributes[attribute])
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|