I've been looking through this:
http://datamapper.org/docs/find
But haven't been able to gleam what I'm looking for, though I know it's quite simple.
I have two tables, scans and stations, with the relevant fields:
STATIONS - id (primary key), name
SCANS - id (primary key), item_id, in_station, out_station
Where in_station and out_station are foreign keys to the id field in the stations table.
I have a Scan object
class Scan
include DataMapper::Resource
property :id, Integer, :key => true
property :item_id, Integer
property :in_station, Integer
property :out_station, Integer
end
So right now, I can do Scan.all(:item_id => #barcode) to get all the scans on a particular item, and I've got the in_station id and out_station id. What's the best way of getting the names, though, instead of ids. I assume it's gotta be easier than for every scan calling Station.get(:id=> scan.in_station).
This is easy enough using SQL, but how can I alter Scan/Station to either get the name or have a property that's a Station object, so I can do something like scan.station.name?
EDIT:
I've almost got this working. I have a Station class:
class Station
include DataMapper::Resource
property :id, Integer, :key => true
property :name, String
end
and I got rid of property :in_station and property :out_station in Scan and replaced with:
belongs_to :in_station, :model => 'Station', :child_key => 'id'
belongs_to :out_station, :model => 'Station', :child_key => 'id'
Which I think/hope is saying "there's a field called in_station which is a foreign key into the Station table and one called out_station which is the same". Indeed, in_station and out_station are now instances of Station, BUT, they're the object. Even though in_station and out_station are different values, I'm getting the same object for each on every Scan. What am I doing wrong, how can I indicate that in_station and out_station are both references to Station but, when their ids are different, I expect different objects.
How about doing this:
class Station
include DataMapper::Resource
property :id, Serial
# rest of the properties
has n, :scans
end
class Scan
include DataMapper::Resource
property :id, Serial
# rest of the properties
belongs_to :station
end
Then you just do this to access the associated station:
station = Station.create
scan = station.scans.create
scan.station # returns the associated station
That should work for you at match your schema.
The assumption is that we don't want to change the underlying SQL schema. So we have to tell DataMapper to use the existing foreign key names (in_station and out_station). The twist is that DataMapper will choke if the association name is the same as the child key. That's why I have the 'my_' prefix on the association names.
class Scan
include DataMapper::Resource
#rest of the properties
belongs_to :my_in_station, :model => 'Station', :child_key => 'in_station'
belongs_to :my_out_station, :model => 'Station', :child_key => 'out_station'
end
Usage
s = Scan.get(id)
s.my_in_station.name
s.my_out_station.name
Related
In Rails, I get a hash using includes:
<% #teste = UserProfile.includes(:mobile_models).group(:name).count %>
The problem is that includes generates a hash like the following:
{nil=>4774, "2610"=>7, "2626"=>4, "2630"=>5, "2760"=>4, "3250"=>3, "355"=>5, "3I607 BlackJack"=>5, "5230"=>13, "5235"=>4, "5310"=>5, "5500"=>5, "5800 Xpress Music"=>16, "6020"=>4, "6120c"=>4, "6131"=>4, "7210"=>5, "A1200r"=>5, "A1900"=>5, "AIKO 70"=>5, "B3410W Ch#t"=>4, "beTouch E100"=>4, "BlackBerry 8320 (Curve)"=>10,....
In my database, I don't find any mobile record with the name "nil". Checking my database, I can't find what might be producing this nil.
The other goal is to sum all values, like this:
<%= sum = #teste.values.sum %>
But when I do this, the 'nil' is added too.
---Update
models/UserProfile
class UserProfile < ActiveRecord::Base
has_and_belongs_to_many :mobile_models, join_table: 'user_profiles_mobile_models', order: 'name'
models/MobileModel
class MobileModel < ActiveRecord::Base
belongs_to :mobile_maker
Because you are grouping by :name, some of the MobileModel or UserProfile objects have the name attribute set to nil. You will need to check both as without seeing the model definition, I can't tell which model has the :name property you are grouping on. If you can share the model code, I can be more explicit.
If both models have a name attribute, you can be more explicit in your group statement:
UserProfile.includes(:mobile_models).group('mobile_models.name')
or...
UserProfile.includes(:mobile_models).group('user_profiles.name')
Also, if a number of your users do not have any mobile_models to include, I believe they will get dumped into the nil grouping as well.
You are getting that hash because of group(:name).
That means you have 4774 records who's name is nil.
I want to know field name corresponding to table caption for a given model in Rails.
I am displaying captions using a query model.
query.columns.map{|q| q.caption}
=> ["Tracker", "Status", "Priority", "Subject", "Assignee", "Target version", "Due date", "% Done"]
Column has names corresponding to captions
query.columns.map{|q| q.name}
=> [:tracker, :status, :priority, :subject, :assigned_to, :fixed_version, :due_date, :done_ratio]
My model looks like
Issue.columns.map{|q| q.name}
=> ["id", "tracker_id", "project_id", "subject", "description", "due_date", "category_id", "status_id", "assigned_to_id", "priority_id", "fixed_version_id", "author_id", "created_on", "updated_on", "start_date", "done_ratio", "estimated_hours", "parent_id"]
I want to get field name(the db field name) corresponding to a caption from the above information.
Sample association in the model
belongs_to :assigned_to, :class_name => 'Principal', :foreign_key => 'assigned_to_id'
So for above association i want to know the foreign key.
for assigned_to i want 'assigned_to_id'
The reflections hash holds this kind of information:
Issue.reflections['assigned_to'].foreign_key
You can also get other information, such as the class (.active_record) or the type of association (.macro). Prior to rails 4.2, the keys of this hash are symbols and not strings.
The correct way for Rails 4.2 is:
Issue.reflections['assigned_to'].options[:foreign_key]
Note that "assigned_to" is a string according to API:
Returns a Hash of name of the reflection as the key and a
AssociationReflection as the value.
http://api.rubyonrails.org/classes/ActiveRecord/Reflection/ClassMethods.html#method-i-reflections
I'm posting this here in case this helps anyone else. I was trying to get the foreign key from proxy_association inside of an association extension.
You can get the reflection by simply using proxy_associtation.reflection.
Then, using #Frederick Cheung's method above, you can get the foreign_key like so:
reflection = proxy_association.reflection
reflection.foreign_key
You can also get the class_name in the same way:
reflection = proxy_association.reflection
reflection.class_name
In my rails app, i am using a legacy database.
class Expression < ActiveRecord::Base
set_table_name "EXPRESSION"
set_primary_key "EXP_ID"
belongs_to :sub, :foreign_key => "EXP_SUB_FK"
end
To save an entry in the 'EXPRESSION' table, i am using the following code in my controller method:
#expression = Expression.create(
:EXP_ID => 7,
:EXP_SUB_FK => 99991886,
:EXP_STRENGTH => 'strong',
:EXP_ADDITIONAL_STRENGTH => 'intense',
:EXP_COMPONENT_ID => 43444
)
I have to manually set the EXP_ID each time i save an entry (i will get the id from another table), but the above code does not save the EXP_ID. All the other values are saved except for the EXP_ID.
If i comment out 'set_primary_key "EXP_ID"' in the Expression model, it works but i need to define EXP_ID as primary key.
Is there a way of allocating a value for a primary key when saving an entry to the dbase?
I would be grateful if anyone can provide me with some hint.
Set the EXP_ID in a before_save filter defined in the the Expression model.
UPDATE:
Added Sample:
before_save :set_exp_id
def set_exp_id
self.exp_id = 5555555
end
I'd like to update a massive set of document on an hourly basis.
Here's the
fairly simple Model:
class Article
include Mongoid::Document
field :article_nr, :type => Integer
field :vendor_nr, :type => Integer
field :description, :type => String
field :ean
field :stock
field :ordered
field :eta
so every hour i get a fresh stock list, where :stock,:ordered and :eta "might" have changed
and i need to update them all.
Edit:
the stocklist contains just
:article_nr, :stock, :ordered, :eta
wich i parse to a hash
In SQL i would have taken the route to foreign keying the article_nr to a "stock" table, dropping the whole stock table, and running a "collection.insert" or something alike
But that approach seems not to work with mongoid.
Any hints? i can't get my head around collection.update
and changing the foreign key on belongs_to and has_one seems not to work
(tried it, but then Article.first.stock was nil)
But there has to be a faster way than iterating over the stocklist array of hashes and doing
something like
Article.where( :article_nr => stocklist['article_nr']).update( stock: stocklist['stock'], eta: stocklist['eta'],orderd: stocklist['ordered'])
UPDATING
You can atomically update multiple documents in the database via a criteria using Criteria#update_all. This will perform an atomic $set on all the attributes passed to the method.
# Update all people with last name Oldman with new first name.
Person.where(last_name: "Oldman").update_all(
first_name: "Pappa Gary"
)
Now I can understood a bit more. You can try to do something like that, assuming that your article nr is uniq.
class Article
include Mongoid::Document
field :article_nr
field :name
key :article_nr
has_many :stocks
end
class Stock
include Mongoid::Document
field :article_id
field :eta
field :ordered
belongs_to :article
end
Then you when you create stock:
Stock.create(:article_id => "123", :eta => "200")
Then it will automaticly get assign to article with article_nr => "123"
So you can always call last stock.
my_article.stocks.last
If you want to more precise you add field :article_nr in Stock, and then :after_save make new_stock.article_id = new_stock.article_nr
This way you don't have to do any updates, just create new stocks and they always will be put to correct Article on insert and you be able to get latest one.
If you can extract just the stock information into a separate collection (perhaps with a has_one relationship in your Article), then you can use mongoimport with the --upsertFields option, using article_nr as your upsertField. See http://www.mongodb.org/display/DOCS/Import+Export+Tools.
I have several similar models ContactEmail, ContactLetter, etcetera.
Each one belongs_to a Contact
Each contact belongs_to a Company
So, what I did was create a virtual attribute for ContactEmail:
def company_name
contact = Contact.find_by_id(self.contact_id)
return contact.company_name
end
Question: How can I get an easy list of all company_name (without duplicates) if I have a set of ContactEmails objects (from a find(:all) method, for example)?
When I try to do a search on ContactEmail.company_name using the statistics gem, for example, I get an error saying that company_name is not a column for ContactEmail.
Assuming your ContactEmail set is in #contact_emails (untested):
#contact_emails.collect { |contact_email| contact_email.company_name }.uniq
You don't need the virtual attribute for this purpose though. ActiveRecord sets up the relationship automatically based on the foreign key, so you could take the company_name method out of the ContactEmail model and do:
#contact_emails.collect { |contact_email| contact_email.contact.company_name }.uniq
Performance could be a consideration for large sets, so you might need to use a more sophisticated SQL query if that's an issue.
EDIT to answer your 2nd question
If company_name is a column, you can do:
ContactEmail.count(:all, :joins => :contact, :group => 'contact.company_name')
On a virtual attribute I think you'd have to retrieve the whole set and use Ruby (untested):
ContactEmail.find(:all, :joins => :contact, :select => 'contacts.company_name').group_by(&:company_name).inject({}) {|hash,result_set| hash.merge(result_set.first=>result_set.last.count)}
but that's not very kind to the next person assigned to maintain your system -- so you're better off working out the query syntax for the .count version and referring to the column itself.