What is the best approach to save multiple temperature-curves (which are measured at the same time) in a Database using Rails and SQL - sql

what is the best approach to save multiple temperature-curves by using Ruby On Rails and a SQL-database. The temperature curves are are measured at the same time. And the time for each measured value musst be stored in seconds.
This picute show my problem in an UML. But the assoziation between timeline and curve-measurment isn't correct. Each timeline-value can have several curve-measurments but not in the same curve. In the same curve alle timeline-values must be unique.
In this solution all timeline-values can have several curve-measurments. This ist correct but in this picutre a timeline-value can have several curve-mesaurments in the same curve and that is wrong.
I hope you understand my problem and you can give me some hint to a better approach.

It looks like your CurveMeasurement should be a join between Curve and Timeline:
class Curve < ActiveRecord::Base
has_many :curve_measurements
...
end
class Timeline < ActiveRecord::Base
has_many :curve_measurements
...
end
class CurveMeasurement < ActiveRecord::Base
belongs_to :curve
belongs_to :timeline
validates :curve_id, uniqueness: { scope: :timeline_id }
validates :timeline_id, uniqueness: { scope: :curve_id }
...
end
The important parts for your requirements are the uniqueness scopes in the CurveMeasurement model - this ensures that you can't have more than one measurement for a given curve at a given timeline point.
It would also be possible to do this without the timeline value being a separate model:
class Curve < ActiveRecord::Base
has_many :curve_measurements
...
end
class CurveMeasurement < ActiveRecord::Base
belongs_to :curve
validates :timeline_value, uniqueness: { scope: :curve_id }
...
end
If you wanted to enforce a discrete set of timeline_values, you can use further validations: either numericality or inclusion (see http://guides.rubyonrails.org/active_record_validations.html )

If I understand correctly, a measurement for a given curve is a value, measured at a specific time. And you want to be able to find all values, for all curves, at any given time.
At the same you want to be able to constrain there is only measurement per time, per curve. You can specifically do that in your second model as well.
In your model, your curve_measurements would look like
t.curve_id
t.timeline_id
t.value
You can then specify a constraint (depends on your database, that the combination curve_id, timeline_id has to be ok.
One wonders, if Timeline offers nothing more than just the time in seconds, why not drop that level of indirection?
Granted, if you have Timeline you can just write timeline.curve_measurements, but if you drop the necessity of the timelines table, and just add the time (or timeline) value directly to the curve_measurements table, your table would look something like
t.curve_id :integer, references: curves
t.measured_at :time
t.value
and then to get all measurements at a certain time, just write CurveMeasurement.where(:measured_at => ....)
Which is easier to query (one join less). Also to make sure there is only measurement per curve, per time, you just have to add the similar constraint, specifying that the curve_id, measured_at combination has to be unique.

Related

Rails: Is this a use case for Single Table Inheritance (STI)?

Consider this setup. Please understand that our setup is much more detailed but this is a simple example.
competition which has name. This is an annual competition.
competition_instances which has location, starts_at.
Each competition has sports which has name.
Example:
competition.name: "Super Bowl" has different competition_instances every year but sport remains the same.
Conversely, competition.name: "Olympics" has different competition_instances and different sports in each competition_instance.
Would it be best to create competition_sports and competition_instance_sports with competition_instance_sports as a subclass of competition_sports?
GOAL: Use competition_instance_sports records if they exist, otherwise use the competition_sports record. In our real world app, each competition/competition_instance can have 20-50 sport records. How can we best achieve?
Based on what I understand from the question I cannot see where STI will be helpful in this situation. However a join table will get you where you want.
I suggest creating a new table sports, this model will have all the specific details of each sport. The competition_instance.rb will have one/many sport.rb. competiton.rb will have many sports through competition_instance.rb.
competition.rb
Class Competition < ActiveRecord::Base
has_many :competition_instances
has_many :sports, through: :competition_instances
end
competition_instance.rb
Class CompetitionInstance < ActiveRecord::Base
belongs_to :competition
belongs_to :sport
end
sport.rb
Class Sport < ActiveRecord::Base
has_many :competition_instances
end
By using this design you will be able to achieve the following:
1- You will have your predefined sports in your database along with their specific properties.
2- Each competition will have .sports which will give all the sports in this competition for the olympics case.
3- You will be able to set specific properties for each competition instance (example event_start_time and event_end_time) in the competition instance table.
I'm just thinking of the case where there are standard sports which are always in the Olympics and some which are added on, such as those proposed by the host country.
I would use Polymorphic Associations, in a "reverse manner".
class Competition < ActiveRecord::Base
has_many :competition_instances
has_many :competition_sports, as: :event
end
class CompetitionInstance < ActiveRecord::Base
belongs_to :competition
has_many :competition_sports, as: :event
def events_array # neater by sacrificing ActiveRecord methods
competition.competition_sports + competition_sports
end
def events # messier, returns ActiveRecord relationship
CompetitionSport.where( " ( event_id = ? AND event_type = 'Competition' ) OR
( event_id = ? AND event_type = 'CompetitionInstance')", competition_id, id )
end
end
class Sport < ActiveRecord::Base
has_many :events, as: :competition_sport
end
class CompetitionSport < ActiveRecord::Base
belongs_to :sport
belongs_to :event, polymorphic: true
end
This allows:
competition.competition_sports # standard sports
competition_instance.competition_sports # only those specific for this instance
competition_instance.events # includes sports from both
Aiming at the original question of "Is this a use case for STI", it will be difficult to say if this is or not without seeing the full complexity of your environment. But here's are some things to consider:
Abridged from How (and When) to Use Single Table Inheritance in Rails - eugenius blog:
STI should be considered when dealing with model classes that share much of the same functionality and data fields, but you want more granular control over extending or adding to each class individually. Rather than duplicate code or forego the individual functionalities, STI permits you to use keep your data in a single table while writing specialized functionality.
You've simplified your example, but it sounds like competition and competition_instance are NOT essentially the same object, with minor behavioral differences. With what you've described, I would probably rename these objects to event and competition, or whatever makes better sense to you in terms of illustrating what these objects are actually representing. I think of 'The Olympics' as a generic event, and '100m Dash' as a competition taking place at The Olympics. Or "The SuperBowl" only hosted one competition in 2014, "SuperBowl XLIX".
You've also tagged this question with database-normalization, which STI won't help. If the attributes differ slightly between your shared objects you'll end up with null fields everywhere.
I refer you to the other answers here to see how you should probably set those objects up to behave as desired.
This is not a case for single table inheritance, because competition_instance is not a substitute for competition and 1 competition can have many competition_instances. So you have 3 tables:
competitions
sports
competition_instances
competition_instances has a foreign key to competitions because 1 competition can have many competition_instances but each competition_instance has exactly one competition.
Whether you attach sports to competitions or competition_instances depends on the specific constraints of your use case. I don't exactly know what you mean by "each competition/competition_instance can have 20-50 sport records". I would expect each competition_instance to have exactly one sport, so you might leave it at that, or you might attach a collection of sports to a competition as well, so that you can retrieve new competitions by sport before there is a competition_instance. I'd need more details on your use case to give you further advice.

Ruby on Rails - has_many relationship with condition that needs a join

I'm working in RoR 3..2.11. I have 4 classes: Person, Agreement, Relationship, and Role. My situation is as follows:
This is in Person:
has_many :relationships
has_many :agreements, {
through: :relationships
}
has_many :current_agreements, {
source: :agreements,
through: :relationships,
conditions: "agreements.start_date <= NOW() AND agreements.end_date >= NOW()"
}
This is in Relationship:
belongs_to Role
A new role has been added to the database ("Past"), so that live agreements can be assigned to another person. Sot the previous person on the agreement still has a relationship to the agreement, but should no longer have it come up under current_agreements. So I need to take into account relationships.role.name. Something like this:
has_many :current_agreements, {
source: :agreements,
through: :relationships,
conditions: "agreements.start_date <= NOW() AND agreements.end_date >= NOW() AND role.name != 'Past'"
}
The issue here is pretty clear cut, role is not in the query so role.name fails. Is there a way to join the role table by the relationships.id for the association?
I've thought of redefining current_agreements as a method instead, but the project needs it to be an association in certain places so I'd really rather just redefine the association instead of re-factoring the whole thing.
I think that current_agreements shouldn't be an association. Does it make sense to ever say
#person.current_agreements << #agreement
? If so, would this set start date and end date, and the associated role?
You say you don't want to refactor it but you could spend more time trying to bash a square peg into a round hole by keeping it as an association.
What about a named scope on Agreement like
#in Agreement
scope :current, includes(:role).where("agreements.start_date <= NOW() AND agreements.end_date >= NOW() AND role.name != 'Past'")
Then you can say
#person.agreements.current
I think that Max Williams is right. This should not be a relation, and I like the Max's approach.
But something that sounds complicated, it's that you don't want to refactor. Remember that one important thing when you design software is to be prepared for the change. If it's difficult to refactor, maybe you should take a look to your tests, or the way that your classes are coupled.
Take a look to the Max's approach, it's simple and clear. And with Ruby/Rails (and of course with tests) the refactor could be enjoyable, to get your desirable behavior.
I like this book. It could explain better than me, my previous words.

Association between one model and an attribute of another

I'm trying to create an association for a beta meat-sale application between one model, Cuts, and the "animal_type" attribute of another model, Animal, such that I could list all the cuts associated with a particular animal_type (or associated with an animal that has that type as an attribute).
In other words, if animal_type is "cow", I should be able to call up a list of all the cuts (ribeye, tenderloin, etc) associated with cows. I'm new to Rails, and this is fairly above my head.
My idea was to create an animal_type column in Cuts and Animals, to associate each cut with a type of animal, so I could do something along the lines of
#cuts = Cut.where(:animal_type => Animal::animal_type[:Cow])
No idea if that works, though, and what else I need to do to make this association possible. Can anybody help point me towards a way of thinking this through? Or does anyone have any good resources I could look at to help me with this specific problem? I've been looking through Rails Guides, and they're helpful, but they don't really give me a way to answer this.
You could have a Cuts model and an Animal model. Cuts could have a string attribute called "name" which would store the cut type such as ribeye, tenderloin etc. Animal could have a string attribute called animal_type. You could then setup a has_many association between Animals and Cuts. Something like this:
class Animal < ActiveRecord::Base
attr_accessible :animal_type
has_many :cuts
end
class Cuts < ActiveRecord::Base
attr_accessible :name
belongs_to :animals
end
This should be a good start

Need help setting up relationships between models

Rails newbie here struggling with a small project. I am creating a simple ship building tool for a board game I like as an exercise and I am a bit lost.
What do I want to do?
-After creating my Ship model record I want to create the Traits model record that will be associated with the Ship model. After updating a Ship model record I want to update or create the Traits model that will be associated with the Ship model record.
What have I tried?
- Adding the traits to each Ship model record as column variables. I do not think that this is the most effecient way of storing the traits for each of my Ship models. I have a Traits model set up but I do not know how to navigate to it and associate it with my Ship models
What would I like to have when finished?
- An array that is stored in each Ship model record that will list the attributes for each ship with their corresponding values,
i.e. if
trait_list = [trait1 => t1, trait2 => t2, trait3 => t3, trait4 => t4]
ship_traits = [t1, t4].
In the end I would be able to call the traits on my ship diagram page without having to iterate through every single trait, just the ones pertinent to my current model.
I am lost on how I should set up the associations between the models. Any help or kind advice on directions I should be researching would be warmly welcomed. I apologize in advance for my vagueness, again I am a complete newbie.
Cheers,
Nick
I'm not 100% sure this would solve your problem, but you could do something like this:
class Ship < ActiveRecord::Base
has_many :traits
accepts_nested_attributes_for :traits
end
class Trait < ActiveRecord::Base
belongs_to :ship
end
# In your form
- form_for #ship do |f|
- f.fields_for :traits do |ff|
= ff.label :trait_name
= ff.text_field :trait_name
# this will return all the traits for model defined as #ship
#ship.traits
I know it's not an array within the Ship model, but I hear it's a little tricky to set a column in a model to be array. If you want the traits to be unique (as in many ships can have many traits and these traits can belong to many different ships), then you're going to have a has_many :through relationship. If that's the case, let me know and I'll answer again. Or you can take a look at this: http://guides.rubyonrails.org/association_basics.html

BEGINNER: Correct seeds.rb in rails 3

I've just created two models and one "join table". Person, Adress (create_adresses_personss)
class Person < ActiveRecord::Base
has_and_belongs_to_many :streets
end
class Street < ActiveRecord::Base
has_and_belongs_to_many :persons
end
Now I want to add some data to these models in the db/seeds.rb file. The tutorial I follow just adds the objects:
person = Person.create :name => 'Dexter'
street.create[{:streetname => 'street1'},
{:streetname => 'street2'},
{:streetname => 'julianave'},
{:streetname => 'street3'}]
Question 1: Why is persons' data added differently than streets'? Is it just the tutorial that wants to show that there are many ways of adding data in the seeds.rb?
Question 2: The tutorial doesn't make the connections/joins in the seeds.rb. It does that in the rails console;
>>p1 = Person.find(1)
>>s1 = Street.find(1)
>>p1.streets << s1
Can't theese connections be made in the seeds.rb file?
Question 3: Would it be better to do this join with a "rich many_to_many-assocciation"?
Thanks for your time and patience with a beginner ;)
1) The first method is creating one object. The second method is creating multiple objects. However, for the second method you would need to do Street.create, not street.create.
2) Yes, you can do that in the seed file the same way.
3) The "Rich many-to-many" you're talking about is an association with a Join Model, I guess you're talking about. This is opposed to just a join table, which is what has_and_belongs_to_many does. To use a join model, you'll want to look up has_many :through. It's generally considered better to always use a proper join model, however I still use HABTM when I just need a quick, simple association. has_many :through allows for more options and more flexibility, but it is a little more complicated to setup (not that much, though). It's your decision.
One way that I like to create seed data for many-to-many associations is setting up one of the models, the adding a tap block that sets up the other models through the association.
Person.create!(:name => "Fubar").tap do |person|
3.times do |n|
person.streets.create!(:streetname => "street #{n}")
end
# OR
person.streets.create!([
{:streetname => "street 1"},
{:streetname => "street 2"},
... and so on
])
end
All tap is doing is executing the block with the object as it's only parameter. I find it convenient for seeds.
One other tip I would toss out there would be to have your model attribute names spaced on the words with underscores.
:street_name instead of :streetname
The difference is more profound when you start wanting to use some of the ActiveSupport helers that take model attributes and turn them into text strings for use in the UI.
e
:streetname.to_s.titleize # "Streetname"
:street_name.to_s.titleize # "Street Name"
And one last nitpick, you might want your join table to be addresses_people not addresses_persons since the rais inflector is going to pluralize person as people. The same would go for your controller on the Person model, PeopleController instead of PersonsController. Though maybe it will work with persons as well.
:person.to_s.pluralize # "people"
:people.to_s.singularize # "person"
:persons.to_s.singularize # "person"