Skip to content

Commit f8db5b4

Browse files
derekcannonrichmolj
authored andcommitted
Implement has_one association for ActiveRecord Adapter (#62)
Add has_one relationship to ActiveRecord adapter
1 parent 66f26f9 commit f8db5b4

File tree

4 files changed

+180
-2
lines changed

4 files changed

+180
-2
lines changed

lib/jsonapi_compliable/adapters/active_record.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ def associate(parent, child, association_name, association_type)
8080
else
8181
parent.send(association_name) << child
8282
end
83+
elsif association_type == :has_one
84+
parent.send("#{association_name}=", child)
8385
elsif
8486
child.send("#{association_name}=", parent)
8587
end

lib/jsonapi_compliable/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
module JsonapiCompliable
2-
VERSION = "0.10.7"
2+
VERSION = "0.10.8"
33
end

spec/fixtures/employee_directory.rb

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@
3838
create_table :departments do |t|
3939
t.string :name
4040
end
41+
42+
create_table :salaries do |t|
43+
t.integer :employee_id
44+
t.decimal :base_rate
45+
t.decimal :overtime_rate
46+
end
4147
end
4248

4349
class ApplicationRecord < ActiveRecord::Base
@@ -75,6 +81,8 @@ class Employee < ApplicationRecord
7581

7682
has_many :employee_teams
7783
has_many :teams, through: :employee_teams
84+
85+
has_one :salary
7886
end
7987

8088
class Position < ApplicationRecord
@@ -86,6 +94,10 @@ class Department < ApplicationRecord
8694
has_many :positions
8795
end
8896

97+
class Salary < ApplicationRecord
98+
belongs_to :employee
99+
end
100+
89101
class ApplicationResource < JsonapiCompliable::Resource
90102
use_adapter JsonapiCompliable::Adapters::ActiveRecord
91103
end
@@ -125,6 +137,11 @@ class HomeOfficeResource < ApplicationResource
125137
model HomeOffice
126138
end
127139

140+
class SalaryResource < ApplicationResource
141+
type :salaries
142+
model Salary
143+
end
144+
128145
class EmployeeResource < ApplicationResource
129146
type :employees
130147
model Employee
@@ -141,6 +158,10 @@ class EmployeeResource < ApplicationResource
141158
resource: TeamResource,
142159
scope: -> { Team.all },
143160
foreign_key: { employee_teams: :employee_id }
161+
has_one :salary,
162+
resource: SalaryResource,
163+
scope: -> { Salary.all },
164+
foreign_key: :employee_id
144165

145166
polymorphic_belongs_to :workspace,
146167
group_by: :workspace_type,
@@ -183,6 +204,8 @@ class SerializableEmployee < SerializableAbstract
183204
belongs_to :classification
184205
has_many :positions
185206
has_many :teams
207+
208+
has_one :salary
186209
end
187210

188211
class SerializablePosition < SerializableAbstract
@@ -201,3 +224,10 @@ class SerializableDepartment < SerializableAbstract
201224

202225
has_many :positions
203226
end
227+
228+
class SerializableSalary < SerializableAbstract
229+
type 'salaries'
230+
231+
attribute :base_rate
232+
attribute :overtime_rate
233+
end

spec/integration/rails/persistence_spec.rb

Lines changed: 147 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def do_post
4848
end
4949

5050
def do_put(id)
51-
put :update, params: payload.merge(id: id)
51+
put :update, params: payload
5252
end
5353

5454
before do
@@ -149,6 +149,152 @@ def do_put(id)
149149
end
150150
end
151151

152+
describe 'has_one nested relationship' do
153+
context 'for new records' do
154+
let(:payload) do
155+
{
156+
data: {
157+
type: 'employees',
158+
attributes: {
159+
first_name: 'Joe',
160+
last_name: 'Smith',
161+
age: 30
162+
},
163+
relationships: {
164+
salary: {
165+
data: {
166+
:'temp-id' => 'abc123',
167+
type: 'salaries',
168+
method: 'create'
169+
},
170+
}
171+
}
172+
},
173+
included: [
174+
{
175+
:'temp-id' => 'abc123',
176+
type: 'salaries',
177+
attributes: {
178+
base_rate: 15.00,
179+
overtime_rate: 30.00
180+
}
181+
}
182+
]
183+
}
184+
end
185+
186+
it 'can create' do
187+
expect {
188+
do_post
189+
}.to change { Salary.count }.by(1)
190+
191+
salary = Employee.first.salary
192+
expect(salary.base_rate).to eq(15.0)
193+
expect(salary.overtime_rate).to eq(30.0)
194+
end
195+
end
196+
197+
context 'for existing records' do
198+
let(:employee) { Employee.create!(first_name: 'Joe') }
199+
let(:salary) { Salary.new(base_rate: 15.0, overtime_rate: 30.00) }
200+
201+
before do
202+
employee.salary = salary
203+
employee.save!
204+
end
205+
206+
context 'on update' do
207+
let(:payload) do
208+
{
209+
data: {
210+
id: employee.id,
211+
type: 'employees',
212+
relationships: {
213+
salary: {
214+
data: {
215+
id: salary.id,
216+
type: 'salaries',
217+
method: 'update'
218+
},
219+
}
220+
}
221+
},
222+
included: [
223+
{
224+
id: salary.id,
225+
type: 'salaries',
226+
attributes: {
227+
base_rate: 15.75
228+
}
229+
}
230+
]
231+
}
232+
end
233+
234+
it 'can update' do
235+
expect {
236+
do_put(employee.id)
237+
}.to change { employee.reload.salary.base_rate }.from(15.0).to(15.75)
238+
end
239+
end
240+
241+
context 'on destroy' do
242+
let(:payload) do
243+
{
244+
data: {
245+
id: employee.id,
246+
type: 'employees',
247+
relationships: {
248+
salary: {
249+
data: {
250+
id: salary.id,
251+
type: 'salaries',
252+
method: 'destroy'
253+
}
254+
}
255+
}
256+
}
257+
}
258+
end
259+
260+
it 'can destroy' do
261+
do_put(employee.id)
262+
employee.reload
263+
264+
expect(employee.salary).to be_nil
265+
expect { salary.reload }.to raise_error(ActiveRecord::RecordNotFound)
266+
end
267+
end
268+
269+
context 'on disassociate' do
270+
let(:payload) do
271+
{
272+
data: {
273+
id: employee.id,
274+
type: 'employees',
275+
relationships: {
276+
salary: {
277+
data: {
278+
id: salary.id,
279+
type: 'salaries',
280+
method: 'disassociate'
281+
}
282+
}
283+
}
284+
}
285+
}
286+
end
287+
288+
it 'can disassociate' do
289+
do_put(employee.id)
290+
salary.reload
291+
292+
expect(salary.employee_id).to be_nil
293+
end
294+
end
295+
end
296+
end
297+
152298
describe 'has_and_belongs_to_many nested relationship' do
153299
let(:employee) { Employee.create!(first_name: 'Joe') }
154300
let(:prior_team) { Team.new(name: 'prior') }

0 commit comments

Comments
 (0)