associations / json and doing things right

I'm doing stuff with Apps in the App Store. Apps belong to a price tier.
Such that.

App
  belongs_to :tier

Tier
  has_many :apps

All good so far.

I want to monitor when an app changes tier amongst other thing, don't
need a history, but need to record the previous tier.

My plan was to store attributes on the App for tier_code and
previous_tier_code, but this strikes me as wrong because an App belongs
to a Tier at a point in time so I don't need to store the tier code
twice (and I shouldn't).

The main reason I've stuck the tier_code attribute on the App is I wish
to serve up JSON from the AppController's index action. With all the
attributes I need on the App directly I can just format.json { render
:json => @apps } or the like.

What could/should I do, ideally I'd like to remove the tier_code
attribute on the App, and incorporate it in the json via the association
<- looked into this and it made my head spin.

bingo bob wrote in post #969776:

I'm doing stuff with Apps in the App Store. Apps belong to a price tier.
Such that.

App
  belongs_to :tier

Tier
  has_many :apps

All good so far.

I want to monitor when an app changes tier amongst other thing, don't
need a history, but need to record the previous tier.

Then you probably want one of the version plugins such as
vestal_versions.

[...]

The main reason I've stuck the tier_code attribute on the App is I wish
to serve up JSON from the AppController's index action. With all the
attributes I need on the App directly I can just format.json { render
:json => @apps } or the like.

The tier_code definitely belongs on the App -- it's a property of the
App, after all. You should have no misgivings about putting it there.

What could/should I do, ideally I'd like to remove the tier_code
attribute on the App, and incorporate it in the json via the association
<- looked into this and it made my head spin.

Uh, what? You've already got it there as an association. What do you
think you want to do differently? And what "made your head spin" --
that is, what didn't you understand? Statements such as this are
completely unhelpful without more detail.

Or are you saying that App has both a tier_id and a tier_code ? If so,
then you're right; that's terrible.

Best,

Or are you saying that App has both a tier_id and a tier_code ? If so,
then you're right; that's terrible.

oops - yes, that's what I'd doing at the moment - and I'd like to change
that I realise it's terrible. The question I have is if I remove the
tier_code then how do I serve up json from my index action in the
controller together with the apps "associated" tier_code.

bingo bob wrote in post #969803:

Or are you saying that App has both a tier_id and a tier_code ? If so,
then you're right; that's terrible.

oops - yes, that's what I'd doing at the moment - and I'd like to change
that I realise it's terrible. The question I have is if I remove the
tier_code then how do I serve up json from my index action in the
controller together with the apps "associated" tier_code.

Go read the docs for to_json ; this is explained clearly. Pay special
attention to the :include option.

Best,

Have started to look at vestal versions...appears that it might be just
the ticket, thanks for the idea.

To use it, I imagine I have to specify any attributes I wish to version
in the migration file generated by the vestal versions generate script -
that right ?

Not sure it's what I want though - will it allow me to do stuff like
App.versionnumber.attribute?

bb

I've been using it for two different projects now. It's very smooth. All you need to do is put the versioned command in your model, and build your VV table with a rake task, migrate, and you're set. The versions are saved in YAML format in one big text field in the VV table, so there's no need to have custom VV tables based on your model, it just works. Once you have set up VV, you can add it to another model with no further changes by simply adding versioned to that model.

If there is a difference in regular (table-backed) attributes from one version of an object to another, then yes, getting a specific version will give you the complete state of the object as of that version. There's nothing extra you need to do in order to get that, it just works.

But if you want to have related (has_many) attributes and get the value of those as of a particular version of the parent, then you will need to find another solution. There's no way to do that with VV as far as I know.

I also had to do some hacking to Paperclip in order to have versioned attached photos. It's very messy and monkey-like, but if you'd like to see it, let me know.

Walter

Thanks Walter, very clear and useful, it looks right for me - but two
things.

1) Why does it create the user stuff in the vv migration/model - I dont
have users in this app, should I delete those attributes or just not
worry about them, and it'll just work (tm).

2) It seems to be more aimed at REVERTING to previous versions rather
than querying them - to explain, in my app I'd like to keep a history of
price tiers of apple store apps, so each day an App.tier might equal a
different value, I might like to print them all out over time or chart
them or more likely find an apps highest or lowest tier historically -
is that easy/doable with VV?

It looks very powerful.

Thanks

bb

If what you want to do is store a set of values for something varying
over time and wish to query the set, pick out max and min and so on
then I suggest this is not best served by versioning. Instead model
it in the normal way. So App has_many price_tiers, PriceTier
belongs_to app, and a PriceTier has a date field you can query on.

Colin

1) Why does it create the user stuff in the vv migration/model - I dont
have users in this app, should I delete those attributes or just not
worry about them, and it'll just work (tm).

The user stuff relates to which user made these changes, nothing else. VV can do multi-user edits and tracks which user made each edit. Very powerful stuff, but I haven't used that feature yet.

2) It seems to be more aimed at REVERTING to previous versions rather
than querying them - to explain, in my app I'd like to keep a history of
price tiers of apple store apps, so each day an App.tier might equal a
different value, I might like to print them all out over time or chart
them or more likely find an apps highest or lowest tier historically -
is that easy/doable with VV?

If what you want to do is store a set of values for something varying
over time and wish to query the set, pick out max and min and so on
then I suggest this is not best served by versioning. Instead model
it in the normal way. So App has_many price_tiers, PriceTier
belongs_to app, and a PriceTier has a date field you can query on.

Colin

I concur. All I have ever used it for is reverting. I can only query the current model, since the pickled objects in the VV table aren't much good for that (barring raw text matching). I make a little "pager" control in the edit view and step through the available versions, the user can pick one and decide to revert to it by saving the object while it is reverted to that particular state (creating a new max+1 version that is a copy of version N).

Walter

If what you want to do is store a set of values for something varying
over time and wish to query the set, pick out max and min and so on
then I suggest this is not best served by versioning. Instead model
it in the normal way. So App has_many price_tiers, PriceTier
belongs_to app, and a PriceTier has a date field you can query on.

Colin

Thanks Colin, realised this is the way to go.
Unless I'm mistaken I can just use the created_at date field to query
on?

If created_at suits your need then certainly.

Colin