Using two keys in a Model

Hi, i need an approach to tackle this problem:

In an ActiveRecord Model, i need to generate the key for the record
given the year

That is: i know for every new record MYSQL will enforce that the id
field will be unique. What i need is this:

MyTable
id: integer
year: integer
number: integer

Mytable.new(2007).save
Mytable.new(2007).save
Mytable.new(2007).save
Mytable.new(2008).save
Mytable.new(2008).save
Mytable.new(1999).save
Mytable.new(2008).save
Mytable.new(2007).save

Records:
id year number
1 2007 1
2 2007 2
3 2007 3
4 2008 1
5 2008 2
6 1999 1
7 2008 3
8 2007 4
etc…

How can i acomplish (and enforce) this?

Thank you!

You are swimming up stream without a good reason.

rec = MyTable.find(:year => 2007)
rec = MyTable.new(:year => 2007) if rec.nil?

You can then put the above in a class method and be done with it. Why
generate computed keys when you do not need to?

Michael

On Jun 13, 9:57 am, Emmanuel O. [email protected]

MichaelLatta wrote:

You are swimming up stream without a good reason.

rec = MyTable.find(:year => 2007)
rec = MyTable.new(:year => 2007) if rec.nil?

You can then put the above in a class method and be done with it. Why
generate computed keys when you do not need to?

Michael

On Jun 13, 9:57 am, Emmanuel O. [email protected]

I have to generate unique records with this format (given my user
specifications). The user needs to number, let’s say, “sheets of paper”
begining with 1 for the first of the year, and reseting every time a
year pass. So i need this:


SHEET 2007 / 1

SHEET 2007 / 2

SHEET 2007 / 3

And so on… when the year changes to 2008, then


SHEET 2008 / 1

SHEET 2008 / 2

SHEET 2008 / 3

SHEET 2008 / 4

etc…

I want to put this in a “sheets” table. So i need the former structure:

TABLE:
sheets.
STRUCTURE:
id: integer
year: integer
number: integer

And make the register unique given the year.

ej:

id, year, number
1 2007 1
2 2007 2
3 2007 3
4 2007 4
5 2008 1 << Begins again
6 2008 2
7 2008 3
8 2008 3 << THIS SHOULD NOT HAPPEN!!!

etc…

This is not something --I-- want to do, is because of the contraints of
the document management on the place i want to implement the system. I’m
worried about the thought of duplicated numbers on my sheets table, just
like the example above.

So i need a reason to ENFORCE that behavior

rec = MyTable.find_or_create_by_year(2007)

But I second Michael’s question. If you explain what your table
really needs to do (i.e., why is multiple records for the same
“year” desirable), then perhaps you can get a better response.

My gut feeling is that you are looking for a situation where Year
has_many Numbers (i.e., not one table, but two), but you haven’t
presented enough information to really reach that conclusion.

-Rob

Rob B. http://agileconsultingllc.com
[email protected]

Emmanuel O. wrote:

On Jun 13, 9:57 am, Emmanuel O. [email protected]

I have to generate unique records with this format (given my user
specifications). The user needs to number, let’s say, “sheets of paper”
begining with 1 for the first of the year, and reseting every time a
year pass. So i need this:

Take a look at acts_as_list.


Cheers,

  • Jacob A.

Rob B. wrote:

rec = MyTable.find_or_create_by_year(2007)

But I second Michael’s question. If you explain what your table
really needs to do (i.e., why is multiple records for the same
“year” desirable), then perhaps you can get a better response.

My gut feeling is that you are looking for a situation where Year
has_many Numbers (i.e., not one table, but two), but you haven’t
presented enough information to really reach that conclusion.

-Rob

Rob B. http://agileconsultingllc.com
[email protected]

I’m getting a little annoyed of --MY-- inability to explain my needs…
:frowning:
Ok, i’ll try again (sorry, my first language is spanish).

Ok, here we go:

Imagine you need to record things that happen every year. Events. Ok, so
you begin like this:

Table:
Events_in_2007
Records:
id, description

So every new record you get a nice and shiny, unique record for every
new event that happens:

Events_in_2007:
id, description
1, “First event of 2007”
2, “Second event of 2007”
3, “Fourth event of 2007” << Oh oh, the user thinks this is the Fourth
event, but dosn’t matter, by the id of the table i know it’s not the
fourth but the third record, so let’s go on.
4, “Very important event”
5, …

Ok, you have the picture.

NOW: one year goes by, and i need to keep records for the new year. What
do i do? Well, first thing i come up with is opening an Events_in_2008
table!

Table:
Events_in_2008
Records:
id, description

Events_in_2008:
id, description
1, “First event of 2008”
2, “Second event of 2008”
3, “Fourth event of 2008” << Oh oh, the user thinks this is the Fourth
event, but no matter, by the id of the table i know it’s not the fourth
but the thirs, so let’s go on.
4, “Very important event”
5, …

And that’s all, but…

Obviusly, to create aditional tables for every year is not an option. I
need to merge an arbitrary number of “Events_of_INSERT-A-YEAR” tables
into a single structure, making imposible to have two events with the
same number of event for a given year.

WHY? Because my client orgranizes the information like that. I absolutly
cannot change that, he has a lot of boxes labeled with the year, in
every box he has a paper representing an event, every paper has a number
that is not repeating itself for that year:

BOX FOR 2006

| |
| etc… |
| 3) document for Event three of 2006 |
| 2) document for Event two of 2006 |

1) document for Event one 0f 2006

BOX FOR 2007

| |
| etc… |
| 4) document for Event four of 2007 |
| 3) document for Event three of 2007 |
| 2) document for Event two of 2007 |

1) document for Event one 0f 2007

BOX FOR 2008
ETC…

My application has to enforce that behaviour so no two documents for a
given year could have the same document number.

I want to model this with ActiveRecord, and don’t know how

Emmanuel O. wrote:

Ok, you have the picture.

And that’s all, but…
that is not repeating itself for that year:
BOX FOR 2007
ETC…

My application has to enforce that behaviour so no two documents for a
given year could have the same document number.

I want to model this with ActiveRecord, and don’t know how

To enforce (almost) uniqueness of event numbering within a year use:

validates_uniqueness_of :eventnumber, :scope => :year

Almost because you may still skip the validation with update_attribute.

To make it easy to order events within a given year use acts_as_list as
previously stated.

Hope this clears things up for you.


Cheers,

  • Jacob A.

you can still use acts_as_list

table sheets:
id :integer
year :integer
:position
:active

class Sheets

acts_as_list, :scope => :year

def self.find_active(*options)
with_scope(:find => { :conditions => “active = true” }) do
find(*args)
end
end

def self.deactivate
self.active = false
self.save
end

end

in your controller you can use Sheet.find_active to find only active
Sheets, and @sheet.deactivate to “mark a record as not useful” and
make it not appear in “find_active” anymore. Acts_as_list will get
your numbering for the sheets by year, and that’s it … perhaps :wink:

On 14 Jun., 16:56, Emmanuel O. [email protected]

Thorsten wrote:

you can still use acts_as_list

I second the use of acts_as_list. (By the way, excellent example using
with_scope.)

Another option would be to sort by year on find, then in your view, test
to see if the current event has the same year as the previous. If not,
you know you’ve entered a new year and can visually represent that.

Event.find(:all, :order => ‘year’).each do |event|
previous_event = event if previous_event.nil?

if event.year != previous_event.year
# echo your change in year
else
# display the object as you normally would
end

previous_event = event
end

But again, I second the use of acts_as_list. Much more programmatic. The
solution I just suggested feels very much like PHP.

To make it easy to order events within a given year use acts_as_list as
previously stated.

Hope this clears things up for you.


Cheers,

  • Jacob A.

From “Agile web development with RAILS” :

“acts_as_list… : Newly created children are automatically added to the
end of the list. When a child row is destroyed, the children after it in
the list are moved up to fill the gap”.

If a child row is destroyed, i don’t want other records to change the
numeration, nor i want it to happen in any other case. (in fact… the
record must not be destroyed, but marked as “record not usefull” or
something like that)