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

Add option to specify custom method for has_many relationships creation #1386

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
18 changes: 13 additions & 5 deletions lib/jsonapi/basic_resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -246,10 +246,9 @@ def reflect_relationship?(relationship, options)

def _create_to_many_links(relationship_type, relationship_key_values, options)
relationship = self.class._relationships[relationship_type]
relation_name = relationship.relation_name(context: @context)

if options[:reflected_source]
@model.public_send(relation_name) << options[:reflected_source]._model
_create_to_many_link(relationship, options[:reflected_source])
return :completed
end

Expand All @@ -274,15 +273,24 @@ def _create_to_many_links(relationship_type, relationship_key_values, options)
end
@reload_needed = true
else
unless @model.public_send(relation_name).include?(related_resource._model)
@model.public_send(relation_name) << related_resource._model
end
_create_to_many_link(relationship, related_resource)
end
end

:completed
end

def _create_to_many_link(relationship, related_resource)
relation_name = relationship.relation_name(context: @context)
return if @model.public_send(relation_name).include?(related_resource._model)

if relationship.options[:create_method]
public_send(relationship.options.fetch(:create_method), related_resource._model)
else
@model.public_send(relation_name) << related_resource._model
end
end

def _replace_to_many_links(relationship_type, relationship_key_values, options)
relationship = self.class._relationship(relationship_type)

Expand Down
34 changes: 34 additions & 0 deletions test/controllers/controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1637,6 +1637,40 @@ def test_create_relationship_to_many_join_table_record_exists
assert_equal [502,503,505], post_object.tag_ids
end

def test_create_relationship_to_many_with_create_method_option
PostResource.class_eval do
has_many :super_tags, acts_as_set: true, relation_name: :special_tags, class_name: 'Tag',
create_method: :add_super_tag
def add_super_tag(tag)
tag.update!(name: "#{tag.name}[super]")
@model.special_post_tags.create!(tag: tag)
end
end

set_content_type_header!

tag_502_name = Tag.find(502).name
tag_503_name = Tag.find(503).name

put :create_relationship, params: {post_id: 3, relationship: 'super_tags', data: [{type: 'tags', id: 502}, {type: 'tags', id: 503}]}

assert_response :no_content
post_object = Post.find(3)
assert_equal 2, post_object.special_tags.collect { |tag| tag.id }.length
assert matches_array? [502, 503], post_object.special_tags.collect { |tag| tag.id }
assert_equal "#{tag_502_name}[super]", Tag.find(502).name
assert_equal "#{tag_503_name}[super]", Tag.find(503).name

tag_505_name = Tag.find(505).name

post :create_relationship, params: {post_id: 3, relationship: 'super_tags', data: [{type: 'tags', id: 502}, {type: 'tags', id: 505}]}

assert_response :no_content
post_object.reload
assert_equal [502,503,505], post_object.special_tag_ids
assert_equal "#{tag_505_name}[super]", Tag.find(505).name
end

def test_update_relationship_to_many_missing_tags
set_content_type_header!
put :update_relationship, params: {post_id: 3, relationship: 'tags'}
Expand Down
5 changes: 4 additions & 1 deletion test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ class TestApp < Rails::Application
config.active_support.halt_callback_chains_on_return_false = false
config.active_record.time_zone_aware_types = [:time, :datetime]
config.active_record.belongs_to_required_by_default = false
unless Rails::VERSION::MAJOR == 5 && Rails::VERSION::MINOR < 2 || Rails::VERSION::MAJOR == 6 && Rails::VERSION::MINOR >= 1
unless Rails::VERSION::MAJOR == 5 && Rails::VERSION::MINOR < 2 ||
Rails::VERSION::MAJOR == 6 && Rails::VERSION::MINOR >= 1 ||
Rails::VERSION::MAJOR > 6
config.active_record.sqlite3.represent_boolean_as_integer = true
end
end
Expand Down Expand Up @@ -221,6 +223,7 @@ class CatResource < JSONAPI::Resource
jsonapi_resources :posts do
jsonapi_relationships
jsonapi_links :special_tags
jsonapi_links :super_tags, only: [:create]
end
jsonapi_resources :sections
jsonapi_resources :iso_currencies
Expand Down