How to restrict text search to a certain subset of the database? - mysql

I have a large central database of around 1 million heavy records. In my app, for every user I would have a subset of rows from central table, which would be very small (probably 100 records each).When a particular user has logged in , I would want to search on this data set only. Example:
Say I have a central database of all cars in the world. I have a user profile for General Motors(GM) , Ferrari etc. When GM is logged in I just want to search(a full text search and not fire a sql query) for those cars which are manufactured by GM. Also GM may launch/withdraw a model in which case central db would be updated & so would be rowset associated with GM. In case of acquisitions, db of certain profiles may change without launch/removal of new car. So central db wont change then , but rowsets may.
Whats the best way to implement such a design ? These smaller row sets would need to be dynamic depending on user activities.
We are on Rails 2.3.5 and use thinking_sphinx as the connector and Sphinx/MySQL for search and relational associations.

how about using has_many :through
class Manufacturer
class Car
class ManufacturerCarRelation
Manufacturer
has_many :manufacturer_car_relations
has_many :cars through => manufacturer_car_relations
ManufacturerCarRelation
belongs_to :manufacturer
belongs_to :car

Maybe you want to define your index with something like this:
class Car
define_index do
indexes description
has 'cars.manufacturer_id', :as => :manufacturer_id, :type => :integer
end
end
and then use field conditions, like:
Car.search "red", :conditions => {:manufacturer_id => gm.id}
or attribute filters:
Car.search "red", :with => {:manufacturer_id => gm.id}

Related

Using form to update has_many through join table

I am short of implementation ideas for my rails project. at this point it seems impossible to implement in rails.
I am cloning a sort of accounting software into a web app using rails framework for small manufacturing companies to keep track of their products stock in their different distribution branches.
I have 3 different models: "Product", "Branch" & "Accumulator"
class Branch < ActiveRecord::Base
has_many :accumulators
has_many :products, :through => :accumulators
end
class Product < ActiveRecord::Base
has_many :accumulators
has_many :branches, :through => :accumulators
def self.search(search)
if search
where('name LIKE ?', "%#{search}%")
end
end
class Accumulator < ActiveRecord::Base
belongs_to :product
belongs_to :branch
end
I am new to rails and after reading up on many to many associations I came across using collections to add products to a branch "#branch.products << Product.all"
Is there a possible way to use a form "number_field_tag" in the branch show view to add multiple of specific products into the join table?
eg
I want to add 10 of (Product) called "garden eggs" to a (Branch) called "lagos branch" to the (Accumulator) join table using a form in Branches show view?
Congratulations for choosing :has_many, through: you will not regret it.
Is the relationship between a product and a branch static?
Or does it change a lot?
In your Accumulator model, add an integer field called amount (count can have conflicts). Then you either create a form for your Accumulators or you add a nested form with for example Cocoon.
This way you can add Accumulators to your Branch with a certain Product and a certain amount.
Off topic:
Here is an article about why has_many through has some advantages:
http://blog.flatironschool.com/why-you-dont-need-has-and-belongs-to-many/
If you have problems with forms I can really recommend SimpleForm and for nice Javascript-assisted fields I recommend Select2.
If the table accumulators needs to save only two things: product_id, and branch_id, you can easily use has_and_belongs_to_many associations.
class Branch < ActiveRecord::Base
has_and_belongs_to_many :products, join_table: 'accumulators'
end
class Product < ActiveRecord::Base
has_and_belongs_to_many :branches, join_table: 'accumulators'
end
And now, there is no need for the third model.
As far as it goes, how to add a relationship, it's pretty easy in this case:
branch = Branch.last
branch.products << Product.create # you don't need to touch the middle table.
Instead of using number_field_tag to ask for plain ids, you can use something fancy like jQuery Chosen Plugin. This plugin will allow you to use tag like input, and will send the ids to the server separated by ,'s.

Combining data from two tables in rails

I have two models, one belongs to the other. They look like this:
class LittleClass < ActiveRecord::Base
has_many :little_class_sessions
end
and
class LittleClassSession < ActiveRecord::Base
belongs_to :little_class
end
LittleClassSession has a column called little_class_id. I want to get all LittleClassSession but also have the associated LittleClass returned to me in the same hash.
Is there some way to do this that's built into Rails? Or is there a clean way to do this?
And is this something that I build into the LittleClass or LittleClassSession model with scope?
When you query ActiveRecord you will get an array of ActiveRecord:Relation. It is a specific entity which starts your query. You can of course join dependent tables (as in your example with one-to-many relation). But you will still need to go over those dependent relations to build whatever object you need.
Here is a sketch of what I mean (assume we search for all little class sessions with specific little class id):
class_sessions = LittleClassSession.includes(:little_class).where(:little_classes => {:id => 1})
class_sessions.each do |relation|
test_hash = relation.attributes.merge!({:little_class => relation.little_class.attributes});
puts test_hash
end
test_hash will include all the attributes of the little class session as well as attributes of the little class under corresponding key.

DataMapper- can I avoid intermediate tables?

I am a total beginner at DataMapper, and have two models:
class ThirdPartyAccount
include DataMapper::Resource
property :access_token, String, :length => 500
belongs_to :user
end
class User
include DataMapper::Resource
property :id, Serial
property :first_name, String
has n, :third_party_accounts, :through => Resource
end
Looking at the SQL logs, it appears to create two tables- users, third_party_accounts and third_party_account_users to join the two. It doesn't appear that the last table is needed- surely the third_party_account table just needs to use it's user_id field to map directly to the user table? Have I accidentally created a many-to-many relationship here?
It's due to this line:
has n, :third_party_accounts, :through => Resource
:through => Resource tells DataMapper to that it's a "has-and-belongs-to-many" relation (each 3rd party account belongs to multiple users and each user has multiple 3rd party accounts), which requires an intermediate table. If this is just a has-many relation (each user has many 3rd party accounts, but each account only belongs to one user), you should just use:
Class User
...
has n, :third_party_accounts
end
See http://datamapper.org/docs/associations.html for more info.

Performance improvement for Rails associated model aggregation

I have a Model called Person and Person has multiple posts. When I want to query post count for each person it takes a long time to process since it needs to iterate over each person and query each posts to get the aggregation.
class Person < ActiveRecord::Base
has_many :posts
end
Output (JSON):
Person1
PostsType1Count: 15
PostsType2Count: 45
Person2
PostsType3Count: 33
.
.
.
I want to calculate all the post count for each Person in a optimum way. What would be the best solution?
Here's one way to do this, if you have a small and pre-defined set of Types
class Person < ActiveRecord::Base
has_many :type_1_posts, :class_name => 'Post', :conditions => 'post_type = 1'
has_many :type_2_posts, :class_name => 'Post', :conditions => 'post_type = 2'
has_many :type_3_posts, :class_name => 'Post', :conditions => 'post_type = 3'
end
Then you can write code that looks like this to get all the data:
#all_people = Person.includes(:type_1_posts, :type_2_posts, :type_3_posts).all
The eager loading of the posts allows the count of each type of post to be available, as well as all the posts of each type.
If you need extra performance for this code, because you perform this query a lot, then you can look into using the Rails counter cache mechanism to keep track of the counts of each type on the Person object.
The beauty of Rails here is that your main display code doesn't need to change during this process of making the code faster for reading (adding a counter cache makes adding/deleting posts slower, so you may not want it in all cases).
Write initial code
Use eager loading to make it faster
Use counter cache to make it even faster
Try this May it will work for you
#In Controller
#persons = Person.all
#In View
#persons.each do |person|
person.posts.count # It will gives all posts count
person.posts.collect{|x| true if x.type==1 }.compact.count #If you want to get the post counts based on type
end
Suppose if you want to get any mehods just check in console or debug is person.methods.sort it will give all methods.
try in rails console person.posts.methods also it will give types also then check counts based on type. because i dont know which fields in posts model. so check it.

Ruby on Rails/Activerecord mySQL modeling

This is a pretty simple question really, but let's say I'm creating a model for Person. Person obviously has first name, last name, age, etc. But the person also has contact info consisting of things like address line 1, address line 2, city, state, zip, country, phone 1, phone 2, etc...
Does it make more sense to create a model for Person and then list that contact information as tables in the model or to also create, say, a ContactInfo (or Address, etc) model, then associate the Person to ContactInfo through an association (Person has_one ContactInfo/Person has_one Address/Address belongs_to Person, etc)?
Which of these is a better approach and what are the benefits/drawbacks to each method?
edit: in re to j..
So with this approach, would I have to then create an Addressable model?
script/generate model Addressable
class Addressable < ActiveRecord::Base
#stuff here?
end
or is this unnecessary?
Also, would i need to add this line to the create_users.rb:
t.references :addressable, :polymorphic => true
I feel like I'm missing something, but I'm not sure what. I appreciate the help a ton, btw! Thanks!
I'd create separated tables/models for address, phone and stuff like this and would make them polymorphic. Like this:
class Address < ActiveRecord::Base
belongs_to :addressable, :polymorphic => true
end
class Person < ActiveRecord::Base
has_one :address, :as => :addressable
end
I believe this is the best way because later you may need to add, for example, a Company model and it'll be easy to make it addressable.
Edit
Using the address as example, you'd need an Address model, not Addressable.
And you'll have to add
t.references :addressable, :polymorphic => true
or
t.belongs_to :addressable, :polymorphic => true
to your create_addresses migration, so you'll have the addressable_id and addressable_type in the addresses table.
Let me know if you have any other doubts :]
the answer above makes sense, but think about how many fields you need and how many records you have to manage. creating a table for each additional field may be too much effort.
another approach could be something more flexible: create a table (say, person_details) with 3 fields: person_id:integer, field_name:string, field_data:string, then the model:
class PersonDetail < ActiveRecord::Base
belongs_to :person
end
this way you can add whatever additional field you need: phone1..phoneN, address1..addressN, and so on.
another similar approach is to pre-determine fields names, to avoid different labels during inserts:
class PersonDetail < ActiveRecord::Base
belongs_to :person
FIELD_NAMES => { 'Address' => 1, 'Phone' => 2)
end
in this case you'll declare the field_name as integer (because it stores only the value of the hash, not a string).