简体   繁体   中英

Ruby on Rails instantiating active record models recursively from a hash

I have two classes inheriting from ActiveRecord::Base and a User might have many Badge s.

class User < ActiveRecord::Base
  has_and_belongs_to :badges
  has_one :user_info
  accepts_nested_attributes_for :user_info
end
class Badge < ActiveRecord::Base
  has_and_belongs_to :users
end

When I make an API call for a User I get the response below:

{
    "UserInfo": {
        "CursePeriod": null,
        "IsCursed": false,
        "IsBanned": false,
    },
    "Badges": [
        {
            "Name": "kayıp",
            "Description": "kim bilir nerede"
        },
        {
            "Name": "çaylak",
            "Description": ""
        }
    ],
    "HasEntryUsedOnSeyler": false,
    "FollowerCount": 0,
    "FollowingsCount": 0,
    "Picture": null
}

And when I pass that json as a hash to User.new I get

ActiveRecord::AssociationTypeMismatch: Badge(#47159034390540) expected,
got {:name=>"kayıp", :description=>"kim bilir nerede"} which is an instance of Hash(#47159016253160)

Is there any way to recursively instantiate all my models from this hash or do I need to do that manually in my User class' initialize method?

What I've come up with to solve this is:

class User < ActiveRecord::Base
  has_and_belongs_to_many :badges

  def initialize(attributes = {})
    create_badges(attributes.delete(:badges))
    super
  end

  def create_badges(badges = [])
    @badges = []
    badges.each do |badge|
      @badges << Badge.new(badge)
    end
  end
end

I am just asking whether ActiveRecord already supports what I am trying to achieve, if so, how?


UPDATE

As for my UserIdentifier class, even though I've included accepts_nested_attributes_for:user_info I still get

ActiveRecord::AssociationTypeMismatch: UserInfo(#46945688683560) expected,
got {:curse_period=>nil, :is_cursed=>false, :is_banned=>false} which is an instance of Hash(#46945670719200)

How I get that error is below

# The hash that I pass to my User class

hash = {:user_info=>{:curse_period=>nil,
                     :is_cursed=>false,
                     :is_banned=>false},
        :badges=>[{:name=>"kayıp", :description=>"kim bilir nerede"},
                  {:name=>"çaylak", :description=>""}],
        :has_entry_used_on_seyler=>false,
        :follower_count=>0,
        :followings_count=>0,
        :picture=>nil}

# Then simply

User.new(hash)

# After the line above, I get the error I mentioned in my update.

ActiveRecord doesn't support multiple initializations, meaning you can't pass an array and expect to have multiple instances of a class, because that's what they reflect, new is used to instantiate a new object belonging to X class that inherits from ActiveRecord::Base .

What you can do is to use create , which can accept an array of hashes containing the data you want for each record you're creating.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM