Comments (5)
Hi @23tux, thanks for your interest! I understand the use case you have, but there are some issues with the implementation I'd like to discuss to find out the best way to solve it:
- What should happen when
scope
is defined inside the class that includesStoreModel::Model
, but then this class is used with.to_type
? We probably could define scopes inside the block like
class Product < ApplicationRecord
attribute :properties, Property.to_array_type do
scope :hidden, ->{ select { |prop| prop.key.start_with?("_") } }
scope :english, locale: "en"
end
end
(props1 + props2).uniq.hidden.english
looks tricky, because in this case in this case it looks like we'd have to implement+
(should we have other math operators? 🙂)
from store_model.
Hi @DmitryTsepelev, thanks for the reply!
- I think defining the scopes inside the block would be just fine, looks good to me!
- Yes, you're right, this looks like we would have to implement all the array methods like
+
,&
,uniq
,select
... Don't know if this is a good solution? Maybe we can find some inspiration in ActiveRecord and how they handle such scope use cases.
Another approach I just tried, defining scopes like this:
class Product < ApplicationRecord
attribute :properties, Property.to_array_type
def properties(scope = :hidden)
Property.public_send(scope, super())
end
end
class Property
def self.hidden(props)
props.select(&:hidden?)
end
end
So when you pass a scope to #properties
it get's filtered.
But this has a major drawback: Doing a product.properties.push(...)
does nothing. It never gets written into the json column, because it's a new array every time.
So I was thinking, what should happen when you add a property to a scoped properties list? Should this throw an error? Or just ignore the changes and only let push to the unscoped array? Maybe we could define a general #add
method on the collection? What do you think?
from store_model.
Yep, adding #add
with the optional scope
param sounds logical. The bad thing is that this approach is still hard to generalize and include to the DSL 😅
from store_model.
I think I have a solution that works for me now:
class Product < ApplicationRecord
attribute :properties, Property.to_array_type, default: []
def properties(scope = :visible)
Property.scope(super(), scope)
end
end
class Property
include StoreModel::Model
attribute :key, :string
attribute :value, :string
def visible?
!hidden?
end
def hidden?
key.to_s.start_with?("_")
end
def self.visible(props)
props.select(&:visible?)
end
def self.hidden(props)
props.select(&:hidden?)
end
def self.all(props)
props.clone
end
def self.scope(properties, scope)
public_send(scope ||= :all, properties).tap do |scoped|
scoped.define_singleton_method(:add) do |prop|
properties.push(prop)
end
scoped.define_singleton_method(:remove) do |key|
properties.delete_if { |prop| prop.key == key }
end
scoped.define_singleton_method(:scope) { scope }
end.freeze
end
end
I know this is specific to my use case, but maybe a similar concept could be implemented into the library. The key takeaways for me where:
- overwriting
#properties
with a scope parameter and callingsuper()
in it to access the underlying json column - making the scoped array frozen so that no one would think a push to a scoped array would change the underlying json column
- defining
#add
and#remove
methods for manipulating the underlying array - defining a
#scope
method for debugging purpose, so that you know which scope is applied
This is not chainable so far, but enough for my specific use case (for now).
from store_model.
Good work on that! Looks like this approach could be generalized – I'll be happy to merge the PR in. If you have some time to play with it a bit more, there are a couple more API design questions to solve:
- We need to find a way to define scopes with DSL like you proposed initially
- We need to generate methods like
Product#properties
dynamically
I think it would be great to isolate the whole thing in the separate module (StoreModel::Model::Scoped
?). Also, we need to have a method in StoreModel::Model
for generating Product#properties
(something like store_model_scope :hidden, :properties, ->(props) { ... }
) and patching Properties
class with scope
method.
from store_model.
Related Issues (20)
- Array of array support HOT 3
- One of depending on another model's column HOT 4
- Validate any Hash HOT 1
- Encrypt attributes HOT 2
- Aliasing an attribute HOT 1
- GraphQL input type fails to cast HOT 4
- ArgumentError: wrong number of arguments (given 1, expected 0) in random model HOT 3
- Assignment Doesn't work in OneOf case HOT 3
- Delegation of `fetch` to `attributes` causes issues HOT 2
- NameError: uninitialized constant StoreModel::Types::ArrayType HOT 3
- Default values for attributes when retrieving the store model HOT 1
- Decoding Custom Types HOT 1
- Allow an option to disallow "UnknownAttributes" behavior HOT 1
- ActiveRecord validation contexts don't propagate HOT 1
- Override methods HOT 3
- Broken defaults in 2.0 HOT 2
- Attribute encryption with ActiveRecord::Encryption HOT 1
- StoreModel Stringifying json when saving. HOT 14
- accepts_nested_attributes_for allow partial updates HOT 2
- [QUESTION] How preserve data on update? HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from store_model.