mavenlink 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +3 -0
- data/README.md +241 -0
- data/Rakefile +28 -0
- data/bin/mavenlink-console +18 -0
- data/doc/ml_logo_lb-primary.png +0 -0
- data/lib/config/specification.yml +1665 -0
- data/lib/mavenlink.rb +134 -0
- data/lib/mavenlink/account_invitation.rb +4 -0
- data/lib/mavenlink/account_membership.rb +4 -0
- data/lib/mavenlink/additional_item.rb +4 -0
- data/lib/mavenlink/assignment.rb +5 -0
- data/lib/mavenlink/attachment.rb +11 -0
- data/lib/mavenlink/backup_approver_association.rb +4 -0
- data/lib/mavenlink/client.rb +116 -0
- data/lib/mavenlink/concerns/custom_fieldable.rb +9 -0
- data/lib/mavenlink/concerns/indestructible.rb +11 -0
- data/lib/mavenlink/concerns/locked_record.rb +30 -0
- data/lib/mavenlink/cost_rate.rb +4 -0
- data/lib/mavenlink/custom_field.rb +4 -0
- data/lib/mavenlink/custom_field_choice.rb +5 -0
- data/lib/mavenlink/custom_field_value.rb +4 -0
- data/lib/mavenlink/errors.rb +47 -0
- data/lib/mavenlink/expense.rb +4 -0
- data/lib/mavenlink/expense_category.rb +4 -0
- data/lib/mavenlink/expense_report_submission.rb +7 -0
- data/lib/mavenlink/external_payment.rb +4 -0
- data/lib/mavenlink/external_reference.rb +24 -0
- data/lib/mavenlink/fixed_fee_item.rb +4 -0
- data/lib/mavenlink/holiday.rb +4 -0
- data/lib/mavenlink/holiday_calendar.rb +4 -0
- data/lib/mavenlink/holiday_calendar_association.rb +4 -0
- data/lib/mavenlink/holiday_calendar_membership.rb +4 -0
- data/lib/mavenlink/invoice.rb +4 -0
- data/lib/mavenlink/logger.rb +62 -0
- data/lib/mavenlink/model.rb +279 -0
- data/lib/mavenlink/organization.rb +4 -0
- data/lib/mavenlink/organization_membership.rb +4 -0
- data/lib/mavenlink/participation.rb +4 -0
- data/lib/mavenlink/post.rb +4 -0
- data/lib/mavenlink/project_template.rb +4 -0
- data/lib/mavenlink/project_template_assignment.rb +4 -0
- data/lib/mavenlink/railtie.rb +7 -0
- data/lib/mavenlink/rate_card.rb +4 -0
- data/lib/mavenlink/rate_card_role.rb +4 -0
- data/lib/mavenlink/rate_card_set.rb +4 -0
- data/lib/mavenlink/rate_card_set_version.rb +30 -0
- data/lib/mavenlink/rate_card_version.rb +4 -0
- data/lib/mavenlink/request.rb +241 -0
- data/lib/mavenlink/resolution.rb +4 -0
- data/lib/mavenlink/response.rb +22 -0
- data/lib/mavenlink/role.rb +5 -0
- data/lib/mavenlink/settings.rb +11 -0
- data/lib/mavenlink/skill.rb +4 -0
- data/lib/mavenlink/skill_category.rb +4 -0
- data/lib/mavenlink/skill_membership.rb +4 -0
- data/lib/mavenlink/specificators/association.rb +13 -0
- data/lib/mavenlink/specificators/attribute.rb +13 -0
- data/lib/mavenlink/specificators/base.rb +24 -0
- data/lib/mavenlink/specificators/validation.rb +27 -0
- data/lib/mavenlink/status_report.rb +4 -0
- data/lib/mavenlink/story.rb +8 -0
- data/lib/mavenlink/story_allocation_day.rb +5 -0
- data/lib/mavenlink/story_dependency.rb +5 -0
- data/lib/mavenlink/story_task.rb +5 -0
- data/lib/mavenlink/tag.rb +5 -0
- data/lib/mavenlink/time_adjustment.rb +4 -0
- data/lib/mavenlink/time_entry.rb +4 -0
- data/lib/mavenlink/time_off_entry.rb +4 -0
- data/lib/mavenlink/timesheet_submission.rb +4 -0
- data/lib/mavenlink/user.rb +5 -0
- data/lib/mavenlink/vendor.rb +4 -0
- data/lib/mavenlink/workspace.rb +21 -0
- data/lib/mavenlink/workspace_group.rb +5 -0
- data/lib/mavenlink/workspace_invoice_preference.rb +4 -0
- data/lib/mavenlink/workweek.rb +4 -0
- data/lib/mavenlink/workweek_membership.rb +4 -0
- data/mavenlink.gemspec +29 -0
- data/spec/lib/mavenlink/account_membership_spec.rb +8 -0
- data/spec/lib/mavenlink/assignment_spec.rb +17 -0
- data/spec/lib/mavenlink/attachment_spec.rb +30 -0
- data/spec/lib/mavenlink/backup_approver_association_spec.rb +9 -0
- data/spec/lib/mavenlink/client_spec.rb +187 -0
- data/spec/lib/mavenlink/concerns/indestructible_spec.rb +13 -0
- data/spec/lib/mavenlink/concerns/locked_record_spec.rb +28 -0
- data/spec/lib/mavenlink/cost_rate_spec.rb +9 -0
- data/spec/lib/mavenlink/custom_field_value_spec.rb +10 -0
- data/spec/lib/mavenlink/expense_report_submission_spec.rb +16 -0
- data/spec/lib/mavenlink/expense_spec.rb +23 -0
- data/spec/lib/mavenlink/external_references_spec.rb +144 -0
- data/spec/lib/mavenlink/holiday_calendar_association_spec.rb +8 -0
- data/spec/lib/mavenlink/holiday_calendar_membership_spec.rb +8 -0
- data/spec/lib/mavenlink/holiday_spec.rb +7 -0
- data/spec/lib/mavenlink/invalid_request_error_spec.rb +9 -0
- data/spec/lib/mavenlink/invoice_spec.rb +176 -0
- data/spec/lib/mavenlink/model_spec.rb +439 -0
- data/spec/lib/mavenlink/post_spec.rb +23 -0
- data/spec/lib/mavenlink/rate_card_set_version_spec.rb +119 -0
- data/spec/lib/mavenlink/record_invalid_error_spec.rb +16 -0
- data/spec/lib/mavenlink/record_not_found_error_spec.rb +9 -0
- data/spec/lib/mavenlink/request_spec.rb +381 -0
- data/spec/lib/mavenlink/response_spec.rb +50 -0
- data/spec/lib/mavenlink/role_spec.rb +9 -0
- data/spec/lib/mavenlink/settings_spec.rb +23 -0
- data/spec/lib/mavenlink/skill_category_spec.rb +7 -0
- data/spec/lib/mavenlink/skill_membership_spec.rb +9 -0
- data/spec/lib/mavenlink/skill_spec.rb +8 -0
- data/spec/lib/mavenlink/specificators/association_spec.rb +25 -0
- data/spec/lib/mavenlink/specificators/attribute_spec.rb +25 -0
- data/spec/lib/mavenlink/specificators/validation_spec.rb +39 -0
- data/spec/lib/mavenlink/story_allocation_day_spec.rb +64 -0
- data/spec/lib/mavenlink/story_dependency_spec.rb +16 -0
- data/spec/lib/mavenlink/story_spec.rb +69 -0
- data/spec/lib/mavenlink/time_adjustment_spec.rb +13 -0
- data/spec/lib/mavenlink/time_entry_spec.rb +43 -0
- data/spec/lib/mavenlink/time_off_entry_spec.rb +9 -0
- data/spec/lib/mavenlink/user_spec.rb +138 -0
- data/spec/lib/mavenlink/workspace_group_spec.rb +25 -0
- data/spec/lib/mavenlink/workspace_spec.rb +431 -0
- data/spec/lib/mavenlink_spec.rb +43 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/support/shared_examples.rb +148 -0
- metadata +267 -0
data/lib/mavenlink.rb
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
|
2
|
+
require 'active_support/core_ext/hash/slice'
|
|
3
|
+
require 'active_support/core_ext/object/try'
|
|
4
|
+
require 'active_support/core_ext/string/inflections'
|
|
5
|
+
require 'active_model'
|
|
6
|
+
require 'yaml'
|
|
7
|
+
require 'json'
|
|
8
|
+
require 'brainstem-adaptor'
|
|
9
|
+
require 'faraday'
|
|
10
|
+
|
|
11
|
+
module Mavenlink
|
|
12
|
+
VERSION = '0.0.1'
|
|
13
|
+
|
|
14
|
+
# Returns HTTP framework
|
|
15
|
+
def self.adapter
|
|
16
|
+
@adapter || Faraday.default_adapter
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# @param value Any valid Faraday adapter
|
|
20
|
+
def self.adapter=(value)
|
|
21
|
+
@adapter = value
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.client
|
|
25
|
+
@client ||= Mavenlink::Client.new
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# @return [Mavenlink::Settings]
|
|
29
|
+
def self.default_settings
|
|
30
|
+
Mavenlink::Settings[:default]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def self.logger
|
|
34
|
+
@logger ||= Mavenlink::Logger.new(nil)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def self.logger=(value)
|
|
38
|
+
@logger = value
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# @param token [String]
|
|
42
|
+
def self.oauth_token=(token)
|
|
43
|
+
default_settings[:oauth_token] = token
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Forces models to perform validations if true
|
|
47
|
+
# If false performs requests without running validations described in specification file
|
|
48
|
+
# Default behavior is not to validate anything
|
|
49
|
+
# @param enabled [true, false]
|
|
50
|
+
def self.perform_validations=(enabled)
|
|
51
|
+
default_settings[:perform_validations] = enabled
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# @param [String] version
|
|
55
|
+
# @return [Api]
|
|
56
|
+
def self.specification
|
|
57
|
+
@specification ||= BrainstemAdaptor::Specification.new(YAML.load_file(File.join(File.dirname(__FILE__), 'config', 'specification.yml')))
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def self.stub_requests(&block)
|
|
61
|
+
stubbed_requests = Faraday::Adapter::Test::Stubs.new(&block)
|
|
62
|
+
self.adapter = [:test, stubbed_requests]
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
require 'mavenlink/settings'
|
|
67
|
+
require 'mavenlink/errors'
|
|
68
|
+
require 'mavenlink/request'
|
|
69
|
+
require 'mavenlink/response'
|
|
70
|
+
require 'mavenlink/client'
|
|
71
|
+
require 'mavenlink/logger'
|
|
72
|
+
require 'mavenlink/concerns/custom_fieldable'
|
|
73
|
+
require 'mavenlink/concerns/indestructible'
|
|
74
|
+
require 'mavenlink/concerns/locked_record'
|
|
75
|
+
require 'mavenlink/specificators/base'
|
|
76
|
+
require 'mavenlink/specificators/attribute'
|
|
77
|
+
require 'mavenlink/specificators/association'
|
|
78
|
+
require 'mavenlink/specificators/validation'
|
|
79
|
+
require 'mavenlink/model'
|
|
80
|
+
require 'mavenlink/account_invitation'
|
|
81
|
+
require 'mavenlink/account_membership'
|
|
82
|
+
require 'mavenlink/additional_item'
|
|
83
|
+
require 'mavenlink/assignment'
|
|
84
|
+
require 'mavenlink/attachment'
|
|
85
|
+
require 'mavenlink/backup_approver_association'
|
|
86
|
+
require 'mavenlink/cost_rate'
|
|
87
|
+
require 'mavenlink/custom_field'
|
|
88
|
+
require 'mavenlink/custom_field_value'
|
|
89
|
+
require 'mavenlink/custom_field_choice'
|
|
90
|
+
require 'mavenlink/expense'
|
|
91
|
+
require 'mavenlink/expense_category'
|
|
92
|
+
require 'mavenlink/expense_report_submission'
|
|
93
|
+
require 'mavenlink/external_payment'
|
|
94
|
+
require 'mavenlink/fixed_fee_item'
|
|
95
|
+
require 'mavenlink/external_reference'
|
|
96
|
+
require 'mavenlink/holiday'
|
|
97
|
+
require 'mavenlink/holiday_calendar'
|
|
98
|
+
require 'mavenlink/holiday_calendar_association'
|
|
99
|
+
require 'mavenlink/holiday_calendar_membership'
|
|
100
|
+
require 'mavenlink/invoice'
|
|
101
|
+
require 'mavenlink/organization'
|
|
102
|
+
require 'mavenlink/organization_membership'
|
|
103
|
+
require 'mavenlink/participation'
|
|
104
|
+
require 'mavenlink/post'
|
|
105
|
+
require 'mavenlink/project_template'
|
|
106
|
+
require 'mavenlink/project_template_assignment'
|
|
107
|
+
require 'mavenlink/skill'
|
|
108
|
+
require 'mavenlink/skill_category'
|
|
109
|
+
require 'mavenlink/skill_membership'
|
|
110
|
+
require 'mavenlink/status_report'
|
|
111
|
+
require 'mavenlink/story'
|
|
112
|
+
require 'mavenlink/story_allocation_day'
|
|
113
|
+
require 'mavenlink/story_dependency'
|
|
114
|
+
require 'mavenlink/story_task'
|
|
115
|
+
require 'mavenlink/tag'
|
|
116
|
+
require 'mavenlink/time_adjustment'
|
|
117
|
+
require 'mavenlink/time_entry'
|
|
118
|
+
require 'mavenlink/time_off_entry'
|
|
119
|
+
require 'mavenlink/timesheet_submission'
|
|
120
|
+
require 'mavenlink/rate_card'
|
|
121
|
+
require 'mavenlink/rate_card_role'
|
|
122
|
+
require 'mavenlink/rate_card_set'
|
|
123
|
+
require 'mavenlink/rate_card_set_version'
|
|
124
|
+
require 'mavenlink/rate_card_version'
|
|
125
|
+
require 'mavenlink/resolution'
|
|
126
|
+
require 'mavenlink/role' # NOTE(SZ): remove
|
|
127
|
+
require 'mavenlink/user'
|
|
128
|
+
require 'mavenlink/vendor'
|
|
129
|
+
require 'mavenlink/workspace'
|
|
130
|
+
require 'mavenlink/workspace_invoice_preference'
|
|
131
|
+
require 'mavenlink/workspace_group'
|
|
132
|
+
require 'mavenlink/workweek'
|
|
133
|
+
require 'mavenlink/workweek_membership'
|
|
134
|
+
require 'mavenlink/railtie' if defined?(Rails)
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
module Mavenlink
|
|
2
|
+
class Client
|
|
3
|
+
ENDPOINT = 'https://api.mavenlink.com/api/v1/'.freeze
|
|
4
|
+
|
|
5
|
+
# @param settings [ActiveSuppport::HashWithIndifferentAccess]
|
|
6
|
+
def initialize(settings = Mavenlink.default_settings)
|
|
7
|
+
@settings = settings
|
|
8
|
+
@oauth_token = settings[:oauth_token] or raise ArgumentError, 'OAuth token is not set'
|
|
9
|
+
@endpoint = settings[:endpoint] || ENDPOINT
|
|
10
|
+
@use_json = settings[:use_json]
|
|
11
|
+
if settings.key?(:user_agent_override)
|
|
12
|
+
@user_agent_override = settings[:user_agent_override]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# TODO: implement with method_missing?
|
|
16
|
+
# Declare API calls client.-->>workspaces<<---.create({})
|
|
17
|
+
Mavenlink.specification.keys.each do |collection_name|
|
|
18
|
+
singleton_class.instance_eval do
|
|
19
|
+
define_method collection_name do
|
|
20
|
+
::Mavenlink::Request.new(collection_name, self)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# @return [Faraday::Connection]
|
|
27
|
+
def connection
|
|
28
|
+
Faraday.new(connection_options) do |builder|
|
|
29
|
+
if @use_json
|
|
30
|
+
builder.headers['Content-Type'] = 'application/json'
|
|
31
|
+
else
|
|
32
|
+
builder.use Faraday::Request::UrlEncoded
|
|
33
|
+
end
|
|
34
|
+
builder.adapter(*Mavenlink.adapter)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Performs custom GET request
|
|
39
|
+
# @param [String] path
|
|
40
|
+
# @param [Hash] arguments
|
|
41
|
+
def get(path, arguments = {})
|
|
42
|
+
Mavenlink.logger.note "Started GET /#{path} with #{arguments.inspect}"
|
|
43
|
+
parse_request(connection.get(path, arguments).body)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Performs custom POST request
|
|
47
|
+
# @param [String] path
|
|
48
|
+
# @param [Hash] arguments
|
|
49
|
+
def post(path, arguments = {})
|
|
50
|
+
Mavenlink.logger.note "Started POST /#{path} with #{arguments.inspect}"
|
|
51
|
+
parse_request(connection.post(path, arguments).body)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Performs custom PUT request
|
|
55
|
+
# @param [String] path
|
|
56
|
+
# @param [Hash] arguments
|
|
57
|
+
def put(path, arguments = {})
|
|
58
|
+
Mavenlink.logger.note "Started PUT /#{path} with #{arguments.inspect}"
|
|
59
|
+
parse_request(connection.put(path, arguments).body)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Performs custom PUT request
|
|
63
|
+
# @param [String] path
|
|
64
|
+
# @param [Hash] arguments
|
|
65
|
+
def delete(path, arguments = {})
|
|
66
|
+
Mavenlink.logger.note "Started DELETE /#{path} with #{arguments.inspect}"
|
|
67
|
+
parse_request(connection.delete(path, arguments).body)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
attr_reader :oauth_token, :endpoint
|
|
73
|
+
|
|
74
|
+
# @return [Hash]
|
|
75
|
+
def connection_options
|
|
76
|
+
if @user_agent_override && @user_agent_override.length > 1
|
|
77
|
+
user_agent = "#{@user_agent_override}"
|
|
78
|
+
else
|
|
79
|
+
user_agent = "Mavenlink Ruby Gem"
|
|
80
|
+
end
|
|
81
|
+
{
|
|
82
|
+
headers: { 'Accept' => "application/json",
|
|
83
|
+
'User-Agent' => "#{user_agent}",
|
|
84
|
+
'Authorization' => "Bearer #{oauth_token}" },
|
|
85
|
+
ssl: { verify: false },
|
|
86
|
+
url: endpoint
|
|
87
|
+
}.freeze
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def parse_request(response)
|
|
91
|
+
if response.present?
|
|
92
|
+
parsed_response = JSON.parse(response)
|
|
93
|
+
else
|
|
94
|
+
return
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
parsed_response.tap do
|
|
98
|
+
Mavenlink.logger.whisper 'Received response:'
|
|
99
|
+
Mavenlink.logger.inspection response
|
|
100
|
+
|
|
101
|
+
case parsed_response
|
|
102
|
+
when Array
|
|
103
|
+
Mavenlink.logger.whisper 'Returned as a plain collection'
|
|
104
|
+
when Hash
|
|
105
|
+
if parsed_response['errors']
|
|
106
|
+
Mavenlink.logger.disappointment 'REQUEST FAILED:'
|
|
107
|
+
Mavenlink.logger.inspection parsed_response['errors']
|
|
108
|
+
raise InvalidRequestError.new(parsed_response)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
rescue JSON::ParserError => e
|
|
113
|
+
raise Mavenlink::InvalidResponseError.new(e.message)
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Mavenlink
|
|
2
|
+
module Concerns
|
|
3
|
+
module LockedRecord
|
|
4
|
+
include Indestructible
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
|
|
7
|
+
included do
|
|
8
|
+
class << self
|
|
9
|
+
protected :new
|
|
10
|
+
protected :create
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# @overload
|
|
15
|
+
def save
|
|
16
|
+
raise RecordLockedError, 'The model is locked and cannot be changed'
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# @overload
|
|
20
|
+
def new_record?
|
|
21
|
+
false
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# @overload
|
|
25
|
+
def persisted?
|
|
26
|
+
true
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
module Mavenlink
|
|
2
|
+
|
|
3
|
+
# The most generic MavenlinkAPI error
|
|
4
|
+
# Eg. service unavailable etc...
|
|
5
|
+
class Error < StandardError
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
# Happens by internal reasons on server side
|
|
9
|
+
# Eg. client cannot parse response format
|
|
10
|
+
class InvalidResponseError < Error
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Another generic API error idenfitying that request is invalid.
|
|
14
|
+
# Eg. invalid parameters passsed in request.
|
|
15
|
+
class InvalidRequestError < Error
|
|
16
|
+
attr_reader :request
|
|
17
|
+
|
|
18
|
+
# @param request [Mavenlink::Request]
|
|
19
|
+
# @param message [String]
|
|
20
|
+
def initialize(request, message = request.inspect)
|
|
21
|
+
@request = request
|
|
22
|
+
super(message)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Identified that a record cannot be changed.
|
|
27
|
+
# Eg. cannot be saved, removed etc.
|
|
28
|
+
class RecordLockedError < Error
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Raised when user is attmping to find unexisting record.
|
|
32
|
+
# Eg. user updates record while somebody else already removed this record.
|
|
33
|
+
class RecordNotFoundError < InvalidRequestError
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Raised when user is trying to save! record specifying invalid attributes.
|
|
37
|
+
# Eg. create! workspace without title.
|
|
38
|
+
class RecordInvalidError < Error
|
|
39
|
+
attr_reader :record # :nodoc:
|
|
40
|
+
|
|
41
|
+
# @param record [Mavenlink::Model]
|
|
42
|
+
def initialize(record)
|
|
43
|
+
@record = record
|
|
44
|
+
super(@record.errors.full_messages.join(", "))
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|