Coder Social home page Coder Social logo

Comments (13)

DmitryTsepelev avatar DmitryTsepelev commented on May 23, 2024 7

According to the docs, array: true option is available only when working with Postgres adapter. In order to have the same thing working for the gem I'll have to register the same modifier inside the gem, and I'm going to figure out how to do that.

At the meantime, here is an instruction how to make it work for your app (might also be helpful when you want custom scalars, e.g. dates):

  1. Define custom types (I keep them in app/types)
class ArrayOfStringsType < ActiveRecord::Type::Value
  def type
    :array_of_strings
  end
end

class ArrayOfIntegersType < ActiveRecord::Type::Value
  def type
    :array_of_integers
  end

  def cast(values)
    return if values.blank?
    values.map(&:to_i)
  end
end
  1. Register them (initializer is a good place to do that):
ActiveModel::Type.register(:array_of_strings, ArrayOfStringsType)
ActiveModel::Type.register(:array_of_integers, ArrayOfIntegersType)
  1. Use them in your model:
class Configuration
  include StoreModel::Model

  attribute :colors, :array_of_strings, default: -> { [] }
  attribute :prices, :array_of_integers, default: -> { [] }
end

from store_model.

DmitryTsepelev avatar DmitryTsepelev commented on May 23, 2024 6

Hi @wooly!

The problem is that default: [] means that the same instance of array will be used as default for all the instances of the TestModel–you can also fix that by using default: -> { [] }. I'm going to fix the examples in docs shortly

from store_model.

DmitryTsepelev avatar DmitryTsepelev commented on May 23, 2024 4

I could be missing it but I'm not seeing any examples/documentation of the default: option
default option is a part of Rails Attributes API, that's why it's not explicitly documented in the gem

Wondering what the use case is for having the default use the same instance of []?
I cannot come up with the example for arrays, but passing the instance works fine for strings (e.g., attribute :status, :string, default: "active"

Another thing I noticed about :default is that it doesn't initialize the default if its an existing ActiveRecord model that you've added a json column to, only new models.
I guess it's the desired behaviour, but it could be fixed for a specific with something like this:

class Configuration
  include StoreModel::Model

  attribute :colors, :array_of_strings, default: -> { [] }
  
  def colors
    attributes[:colors] || []
  end
end

from store_model.

danielvdao avatar danielvdao commented on May 23, 2024 1

@DmitryTsepelev poking here 🙇🏽‍♂️ , no worries if not, but just wondering if there's an update or if we shouldn't expect this for now.

from store_model.

ScotterC avatar ScotterC commented on May 23, 2024 1

I'm also finding this issue due to arrays of strings not working. The Readme says that store_model follows the Attributes API of ActiveRecord which has array: true as an option. But by the errors I'm seeing, it looks like it actually follows the Attributes API of ActiveModel which doesn't have array: true.

from store_model.

exsemt avatar exsemt commented on May 23, 2024

Thanks for your answer! I know, I use also postgres, but in combination with store_model it does not work. But I think that should not matter which adapter you use, it will be great to have this function in store_model.

from store_model.

icecoldmax avatar icecoldmax commented on May 23, 2024

I was just dealing with this yesterday as well! I have a jsonb column where the structure is

{
  foo: [{ bar: "baz"}, { fish: "chips" }],
  apples: [{ bananas: "cherries" }],
  ...
}

I'm also using the jbuilder gem for serialisation and was struggling to get it serialising properly when the attributes were :string.

Using @DmitryTsepelev's array_of_strings workaround worked for me! Thanks!

from store_model.

wooly avatar wooly commented on May 23, 2024

We've now reverted the workaround since there's some broken behaviour:

class TestModel
  include StoreModel::Model

  attribute :group, :array_of_strings, default: []
end

Now in a rails console:

[3] pry(main)> t1 = TestModel.new
#<TestModel group: []>
[4] pry(main)> t1.group << "foo"
[
    [0] "foo"
]
[5] pry(main)> t2 = TestModel.new
#<TestModel group: ["foo"]>
[6] pry(main)> t1.group << "foo"
[
    [0] "foo",
    [1] "foo"
]
[7] pry(main)> t2 = TestModel.new
#<TestModel group: ["foo", "foo"]>

As you can see, assigning to the group of the first object pollutes the groups for all new objects created after.

It might be as simple as adding the following to the ArrayOfStringsType class definition:

def cast(value)
  Array.new(value)
end

from store_model.

ishields avatar ishields commented on May 23, 2024

I could be missing it but I'm not seeing any examples/documentation of the default: option in the docs at all. Wondering what the use case is for having the default use the same instance of []? Another thing I noticed about :default is that it doesn't initialize the default if its an existing ActiveRecord model that you've added a json column to, only new models. Not sure if that is by design? In my case I'm adding to an existing record type so would like to be able to specify a default going forward even for existing records.

from store_model.

samirph avatar samirph commented on May 23, 2024

In my case, using default: -> { [] } was useless.
The workaround by defining a method like this worked alone.

attribute :colors, :array_of_strings

def colors
    attributes[:colors] || []
end

from store_model.

scomma avatar scomma commented on May 23, 2024

Hi, just want to check whether this was closed because it now works or because there's no bandwidth to work on it. Thanks for releasing the gem.

from store_model.

wooly avatar wooly commented on May 23, 2024

I'd be keen to know this too as I have another use case for it. The array approach seems to be supported by attr_json but I'd rather not invest the time in switching to that, so if there's anything I can do to help get this over the line, let me know.

from store_model.

wooly avatar wooly commented on May 23, 2024

Appreciate that @samirph's comment was a long time ago, but anyone who is coming across this issue and having trouble with the default, it's because .blank? will return true for empty arrays as well as nils, which will interfere with the default option.

Changing the cast to the following fixes the issue:

def cast(values)
  return if values.nil?
  values.map(&:to_i)
end

from store_model.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.