-
Notifications
You must be signed in to change notification settings - Fork 0
Advanced mode
In advanced mode, Datasource will optimize your queries even more by SELECT-ing only the database fields that are necessary (instead of table.*).
You can turn advanced mode on by turning off simple mode in the initializer:
Datasource.setup do |config|
config.adapters = [:activerecord, :active_model_serializers]
config.simple_mode = false
endAn example of how the queries look with advanced mode:
class PostSerializer < ActiveModel::Serializer
attributes :id, :title
end
class UserSerializer < ActiveModel::Serializer
attributes :id, :email
has_many :posts
endSELECT id, email FROM users
SELECT id, title, user_id FROM posts WHERE id IN (?)There is a caveat: You will need to tell Datasource which database columns your virtual attributes depend on, as explained below.
If you try to use a model method or virtual attribute in your serializer, you will get an error from Datasource. Since the method computes the value based on some other attributes, you need to tell Datasource what these dependencies are.
To do this, call computed in a datasource_module block like in the below
example. It can depend on database columns, other computed attributes or loaders
(advanced feature).
class User < ActiveRecord::Base
datasource_module do
# The method first_name_initial depends on first_name column
computed :first_name_initial, :first_name
# The method both_initials (in the serializer)
# depends on first_name and last_name columns
computed :both_initials, :first_name, :last_name
end
# method can be in model
def first_name_initial
first_name[0].upcase
end
end
class UserSerializer < ActiveModel::Serializer
attributes :first_name_initial, :both_initials
# method can also be in serializer
def both_initials
object.last_name[0].upcase + object.last_name[0].upcase
end
endSELECT first_name, last_name FROM usersYou can also use Datasource without a specific serializer:
Post.with_datasource.datasource_select(:id, :title, :comments).to_aThis is actually more or less what for_serializer does under the hood. It
determines the arguments for datasource_select from the serializer's metadata.
You can also use for_serializer and then select additional attributes. A real
world example where you might need this is in a loader:
class Comment < ActiveRecord::Base
belongs_to :post
end
class Post < ActiveRecord::Base
has_many :comments
datasource_module do
loaded :newest_comment, group_by: :post_id, one: true do |post_ids|
Comment.for_serializer.where(post_id: post_ids)
.group("post_id")
.having("id = MAX(id)")
.datasource_select(:post_id)
end
end
end
class CommentSerializer < ActiveModel::Serializer
attributes :id, :comment
end
class PostSerializer < ActiveModel::Serializer
attributes :id, :title, :newest_comment
def newest_comment
CommentSerializer.new(object.newest_comment).as_json
end
endIn this case, the CommentSerializer does not need post_id, however we need it
for the loader's group_by. So we used both for_serializer and also
datasource_select(:post_id) to additionally select post_id.