When using Grape Entity, sometimes we want to expose a few fields from an inner/related object. We can simply do this by:
expose(:bar) { |entity| entity.foo.bar }
However if many fields needs this treatment, this can get very repetitive. Is there a way to define delegation / forward so a bunch of expose all are associated with another object?
create a separate entity for foo class, let's call it API::Entities::Foo. then you can
expose :foo, using: API::Entities::Foo
you have to follow REST guidelines to serialize like this. you are dealing with resources. don't break it to flat, cumbersome data structures.
Related
I have a lot of code like this
additional_params = {
date_issued: pending.present? ? pending.date_issued : Time.current,
gift_status: status,
date_played: status == "Opened" ? Chronic.parse("now") : (opened.present? ? opened.date_played : nil),
email_template: service&.email_template,
email_text: service&.email_text,
email_subject: service&.email_subject,
label: service&.label,
vendor_confirmation_code: service&.vendor_confirmation_code
}
SomeService.new(reward, employee: employee, **additional_params).create
The same pattern applies to many models and services.
What is the name of this pattern?
How to refactor the current solution?
Is there a gem to solve this kind of solution? Like draper or something else
To me, that looks a bit like a god object for every type of entity. You expect your service to take care of everything related to your entity. The entity itself just acts as a data container and isn't responsible for its data. That's called an anemic model.
First of all, you need to understand that there can be several representations of the same entity. You can have several different classes that represent a user. On the "List user" page, the class contains just a subset of the information, maybe combined with information from the account system (last login, login attempt etc). On the user registration page, you have another class as it's not valid to supply all information for the user.
Those classes are called data transfer objects. Their purpose is to provide the information required for a specific use case and to decouple the internal entity from the external API (i.e. the web page).
Once you have done that, your service classes will start to shrink and you need fewer custom parameters for every method call.
Now your service class has two responsibilities: To manage all entities and to be responsible for their business rules.
To solve that, you should start to only modify your entities through behaviors (methods) and never update the fields directly. When you do so, you will automatically move logic from your service class to your entity class.
Once that is done, your service classes will be even cleaner.
You can read about Domain Driven Design to get inspired (no need to use DDD, but get inspired by how the application layer is structured in it).
You can try the builder pattern. I am not familiar with a ruby gem, but you can find information here: https://en.wikipedia.org/wiki/Builder_pattern and https://en.wikipedia.org/wiki/Fluent_interface
I'm creating a non-Rails application and using DataMapper as ORM.
For entities which will be mapped to SQL tables I declare classes which include DataMapper::Resource.
The question is. Is it okay to use the instances of these classes as plain objects (pass to methods, manipulate values etc.)? Or they should be used only for persisting data (for instance in Repository classes)?
I'm new in the Ruby world and do not know the conventions.
If I have a User entity, which has methods creates, all etc., is it a good idea to create another class User, which only will store information (will have state - fields and no methods)? Analogue of POJO (Plain old java object) in Java?
I can see creating a wrapper class for a plain object list having some benefits. As you mention in the comment, if you want to store data in different ways then writing distinct classes is useful.
For typical DataMapper or ActiveRecord usage, though, I don't think it's common to create wrapper classes for plain-object lists, especially if you're not adding any methods to the collection. The main reason why it's not common is that query results in ActiveRecord or DataMapper are array-like already. Additionally, you're not really gaining any added functionality by converting your model instances to hashes. Let me show some example:
# collections are array-like
User.all.map(&:name) == User.all.to_a.map(&:name)
# converting a record to a hash doesn't add much
user = User.first
user_hash = user.attributes
user.name == user_hash[:name]
That being said, there is one caveat, and that has to do with chainable methods in the ORM:
# this is valid chaining
User.all.where(name: "max")
# this raises a NoMethodError for 'where'
User.all.to_a.where(name: "max")
where is a ORM method, not an array method. So if you convert the query result to an array you couldn't access it. For this reason, making a distinction between arrays and query collections is useful.
But how much benefit do you really get from creating an empty wrapper class?
class RecordsInMemory
def initialize(query_collection)
#list = query_collection.map(&:attributes)
end
end
records_in_memory = RecordsInMemory.new(User.all)
records_in_memory.list.map(&:name)
# versus ...
records_in_memory = User.all.map(&:attributes)
records_in_memory.map(&:name)
if you think in the long run you will add methods to the plain-object list, then you should make it into a class. But otherwise I think using clearly-named variables suffices.
I am building a REST API in Ruby using Grape.
My frontend is written in AnguarJS and the default datetime serialization made by Grape is not correctly being understood by angulars' date filter. So my idea is to format all the datetime attributes in ruby before sending it.
What is the best approach ?
Is there a generic Time serialization in Grape that I can use ?
If not, is it feasible to perform a deep lookup in a ruby list or map, find all Time instances, and replace them by a formatted string ?
My current solution below is tightly coupled for one attribute, but I would like to extend this formatting to all Time instantes.
result_json.each do | x |
x[:date] = x[:date].strftime("%Y%m%dT%H:%M:%S")
end
If you're using Grape Entity then you can extend the ApiHelper to include a new formatter. For example:
module ApiHelpers
extend Grape::API::Helpers
Grape::Entity.format_with :iso8601 do |date|
date.iso8601 if date
end
end
Once you have done it, you can use it in your Entities like this:
module Entities
class MyModel < Grape::Entity
expose :updated_at, format_with: :iso8601
end
class AnotherModel < Grape::Entity
expose :created_at, format_with: :iso8601
end
end
I believe it's the best way to tackle this problem because you shouldn't change the Time class just to solve a problem in your View layer. Using Grape Entity is a good practice too. You should always shield your API from possible changes in your Models. Also, remember that what you expose through a Rest API are "Resources" and not Models. In fact, a resource can even be a combination of multiple Models and Entities allow you to define a Resource and reuse it wherever you need it. Using entities, you can exclude fields, create fields that are a combination of others fields. It gives you flexibility.
I'm writing a set of REST services and have come upon a problem that I'm sure has an appropriate solution/pattern that's just eluding me.
For instance /api/People/1 will return a serialized representation of PersonDto (which is a pared down representation of the Person domain object created by Entity Framework. I'm using AutoMapper to hydrate PersonDto.
However a second controller (say, /api/Classes/) is going to return different complex object, which may contain one or more Persons, however I want to represent each person in a different way than simply using an existing PersonDto (e.g. I might require more or less fields).
Do I need to define a ClassPersonDto? I'm not sure what the "proper" thing is to do here.
If the model of "person" being passed back in "Classes" is different then the "PersonDto" model, then yes, create a different model. You don't need to, but it's almost always better to keep your classes, including entities, as specific as possible.
I've been reading the MongoDB documentation and Spring adds a _class field by default to the stored data. Is there any way to use this information to have type inference?
For example: There is a an abstract class Animal with three subclasses Dog, Cat, Bird. Say you have a class Zoo which contains a list of animals. In the database you store those Zoo Objects. Is there any function to get a List<Animal> back with Animals that can be upcasted?
I'm using Spring so I prefer to have a solution that would work using the spring-data-mongodb. But an external mapping library would be fine too. I prefer not to write it myself as it seems basic mapping functionality.
Make sure you map all types you mentioned to be stored in the same collection (e.g. using the #Document annotation). Then you can simply execute queries against the collection handing in Animal to the according method on MongoTemplate. The underlying converter will then automatically instantiate the correct types based on the information stored in _class. The same applies to the usage of Spring Data MongoDB repositories.