Help Updating A Collection of Attributes

So I’ve been pretty pleased with myself for the most part. I’ve managed to do just about everything I’ve wanted to do in regards to creating my game. One thing continues to elude me, however, and that is updating a collection of attributes. I can create them and set their default values but I’m having a difficult time figuring out how to update the values. I can pull out each individual attribute and modify it…but it doesn’t save back to the character object it’s attached to.

The collection in question has a number of string attributes (name, type, description, quote) and two array attributes (power tags and weaknesses). I can create them on the character (each character gets set up with 4 of these) and set their default values. I can call each value and display them on the sheet. I can call each value and change them. I just can’t save those changes back to the character object.

Any help or suggestions on where I should look for advice would be greatly appreciated. Thanks!

You need to use the update method to save values in the database. For example:

 char = Character.find_one_by_name("Bob")
 char.update(description: "Some new description")

If you just do char.description = "Some new description" it sets the attribute locally in that function, but doesn’t save it to the database.

If that’s not the issue, let me know how you’re trying to set things.

What if it’s not a single attribute but a single attribute within a collection of attributes. I have a collection of attributes stored together in, let’s say, Attr_Collection. Each character has 4 of these collections set on them. One of the attributes in each collection is “Power Tags”. Power Tags is an array of strings. I can update the specific tag by using…

char.Attr_Collection.sort_by(:name, :order => “ALPHA”)[0].tags.each {|s| s.gsub!(‘Tag 1’, ‘This Was Tag 1’)}

So in the first collection of attributes the tag that reads “Tag 1” becomes “This Was Tag 1”. It throws back the correct set of revised attributes but I don’t know how to save this back onto the character.

I hope that makes sense! I’m probably not doing it in the most efficient manner but this is what I found that works. LOL :slight_smile:

Yeah it’s the same principle whether it’s an array (which is what I assume you’re using there) or a string.

 class Character
    attribute :things, :type => DataType::Array
 end

char = Character.find_one_by_name("Bob")

If all you do is a gsub or a variable assignment, you’re just updating char, a local variable. As soon as the method exits, that variable disappears. The database never got changed. You need to call update to update the database.

For arrays, you have to call update with the whole array.

 new_things = char.things
 new_things.each { |t| t.gsub("X", "Y") }
 char.update(things: new_things)

Yeah, I get how to do it on an individual attribute. It’s saving it back to a collection of attributes that eludes me. So I have the following collected into a collection called ATTR_COLLECTION:

Name (String)
Type (String)
Description (String)
Power Tags (Array of Strings)
Weaknesses (Array of Strings).

I access the group using ATTR_COLLECTION and can manipulate them fine that way but I just don’t know how to make those changes permanent within the collection itself.

Anyway, thanks for the help.

I’m really not sure what you mean by “collection of attributes”. Can you be a little more specific? Maybe provide a little code snippet of what your Ohm database model looks like?

I would expect each of those things to be individual attributes. For example:

 class Character
      attribute :name
      attribute :type
      attribute :description
      attribute :tags, :type => DataType::Array
      attribute :weaknesses, :type => DataType::Array
 end

Then you could do something like

 char.update(name: "Bob", type: "Troll", description: "Bob's Desc", tags: new_tags)

Maybe I’m missing what you’re trying to do.

It’s entirely possible I’m using collections wrong. Here’s what I did.

I declared the attributes here.

module AresMUSH
class COMTheme < Ohm::Model
include ObjectModel

reference :character, "AresMUSH::Character"
attribute :type
attribute :name
attribute :attention, :type => DataType::Integer, :default => 0
attribute :fade, :type => DataType::Integer, :default => 0
attribute :quote
attribute :description
attribute :tags, :type => DataType::Array, :default => []
attribute :weaknesses, :type => DataType::Array, :default => []

end
end

Then I declared it a collection in a Character class like this.

collection :com_themes, “AresMUSH::COMTheme”

That allows me to create the collection like this:

COMTheme.create(character: enactor, type: “Mythos”, name: “Mythos 1”, quote: “Quote Here”, description: “Tag Description”, tags: [“Tag 1”, “Tag 2”, “Tag 3”], weaknesses: [“Weakness 1”])

Each character gets 4 of these collections and I a can access them like this:

char.com_themes

It’s possible, maybe even likely, I’m using them wrong however. It just seemed like the best way to accomlish what I wanted to do.

Thanks!

Ah! I see. That’s a perfectly legit way to use collections; I was just misunderstanding what you were trying to do.

The thing it - it’s not really a collection of ‘attributes’, it’s a collection of other models (COMTheme models, in this case). Since the COMTheme model is just a regular old database model, so you still need to do something special to save changes to the database.

When you do this:

 char.com_themes[0].tags.each {|s| s.gsub!(‘Tag 1’, ‘This Was Tag 1’)}

All you’re doing is changing the copy of com_themes.tags that exists in your local char object. You’re not actually changing the database.

Usually you’d use update if you change a model:

 theme = char.com_themes[0]
 theme.update(quote: 'New quote')

But there’s a shortcut for update called save if you are changing multiple fields at once, which I think is what you’re trying to do:

 theme = char.com_themes[0]
 theme.quote = "New quote"
 theme.description = "New description"
 theme.tags.each { |t| t.gsub!('tag', 'TAG') }
 
 # Then the magic save to save it to the database
 theme.save

Hope that helps.

That got it! Thanks a lot for the help. :slight_smile:

Great! Glad that fixed it.

FWIW you’ll see that in the main Ares code I favor individual update calls over a bunch of field changes followed by save. I’ve found that I’m less likely to forget the all-important database save if I do it every time I’m changing a database field. Otherwise it’s too easy to leave the save off at the end, or to miss saving in both sides of an if/else case, or to move code around and accidentally put something after the save.

Update is more explicit, and redis is so fast that you won’t really see a performance hit even if you do ten field updates in a single command.