Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix association #60

Merged
merged 1 commit into from
Jan 22, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,18 @@ Output:
### Associations
You may include associated objects. Say for example, a user has projects:
```ruby
class ProjectBlueprint < Blueprinter::Base
identifier :uuid
field :name
end

class UserBlueprint < Blueprinter::Base
identifier :uuid
field :email, name: :login

view :normal do
fields :first_name, :last_name
association :projects
association :projects, blueprint: ProjectBlueprint
end
end
```
Expand Down
5 changes: 4 additions & 1 deletion lib/blueprinter/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ def self.field(method, options = {}, &block)
#
# @param method [Symbol] the association name
# @param options [Hash] options to overide defaults.
# @option options [Symbol] :blueprint Required. Use this to specify the
# blueprint to use for the associated object.
# @option options [Symbol] :name Use this to rename the association in the
# JSON output.
# @option options [Symbol] :view Specify the view to use or fall back to
Expand All @@ -95,12 +97,13 @@ def self.field(method, options = {}, &block)
# @example Specifying an association
# class UserBlueprint < Blueprinter::Base
# # code
# association :vehicles, view: :extended
# association :vehicles, view: :extended, blueprint: VehiclesBlueprint
# # code
# end
#
# @return [Field] A Field object
def self.association(method, options = {})
raise BlueprinterError, 'blueprint required' unless options[:blueprint]
name = options.delete(:name) || method
current_view << Field.new(method,
name,
Expand Down
10 changes: 4 additions & 6 deletions lib/blueprinter/serializers/association_serializer.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
class Blueprinter::AssociationSerializer < Blueprinter::Serializer
def serialize(association_name, object, local_options, options={})
if options[:blueprint]
view = options[:view] || :default
options[:blueprint].prepare(object.public_send(association_name), view_name: view, local_options: local_options)
else
object.public_send(association_name)
end
value = object.public_send(association_name)
return value if value.nil?
view = options[:view] || :default
options[:blueprint].prepare(value, view_name: view, local_options: local_options)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, I'm not sure if you intended this or not, but a side effect of this code is that it makes it so that you now always have to have a Blueprint for every association. I think that could be considered a reasonable tradeoff, but I want to make sure we're explicitly making that decision.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ya, so I do not understand how it would work if the associated object does not have a blueprint.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am for having the requirement that any object being serialized within this system must use a blueprint... I've personally been bitten by having both AMS and jbuilder for the same resource far too many times to try to fashion some coexistence between any of them.

end
end
34 changes: 34 additions & 0 deletions spec/integrations/base_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,40 @@
let(:vehicle) { create(:vehicle) }

include_examples 'Base::render'

context 'Given blueprint has ::association' do
let(:result) do
'{"id":' + obj_id + ',"vehicles":[{"make":"Super Car"}]}'
end
let(:blueprint_without_associated_blueprint) do
Class.new(Blueprinter::Base) do
identifier :id
association :vehicles
end
end
before { vehicle.update(user: obj) }
context 'Given associated blueprint is given' do
let(:blueprint) do
vehicle_blueprint = Class.new(Blueprinter::Base) do
fields :make
end
Class.new(Blueprinter::Base) do
identifier :id
association :vehicles, blueprint: vehicle_blueprint
end
end
it('returns json with association') { should eq(result) }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is so implicit and confusing. Maybe we should switch to MiniTest 😜

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok i admin i over-utilized some of rspec's "features" that does make it quite implicit. I'll make more explicit specs going forward =D

end
context 'Given no associated blueprint is given' do
let(:blueprint) do
Class.new(Blueprinter::Base) do
identifier :id
association :vehicles
end
end
it { expect{subject}.to raise_error(Blueprinter::BlueprinterError) }
end
end
end
end
end