Customise database entries for every user - ruby-on-rails

I have an e-commerce site where pricing for the prices are referenced in the prices table under the pricing model.
However, how can i be able to customise prices for individual clients for the same goods. How can i do that using the Price model.
I have tried adding user_id to the table but it seems have to price the same good for every individual client. How can i go about that?
The current table looks like this;
create_table "prices", :force => true do |t|
t.string "country"
t.string "network"
t.decimal "price_euros", :precision => 10, :scale => 3
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.decimal "price_ugx", :precision => 10, :scale => 3
t.decimal "price_kes", :precision => 10, :scale => 3
t.decimal "price_tzs", :precision => 10, :scale => 3
t.decimal "price_usd", :precision => 10, :scale => 3
end

There are various ways of achieving this. If each customer had the same discount across all goods, then you could add a discount attribute to the User model and apply this to the displayed prices.
If you want unique prices across the products which are unique for each user, then I would create a new model called UserPrice and have 3 attributes: user_id, product_id, price.
I would then have a method in my Product model called price_for_user along the following lines:
def price_for_user(user)
UserPrice.find_by_user_id_and_product_id(user.id,self.id).price
end
When iterating over your products in the view, you could write:
<%= #product.price_for_user(current_user) %>
Obviously, you'll need to adjust variables as required for your situation. I would also index the user_id and product_id columns in the UserPrice table for speed.
NB: If it was me, in my controller, I would also consider looking up all UserPrices by user and creating a hash and then in the view displaying the price by doing a lookup in the hash. This might be quicker.
def index
#products = Product.all
#user_prices = UserPrice.where(user_id: current_user.id).index_by(&:product_id)
end
In your view:
<%= #user_prices[product.id].price %>

Related

copy a db table column and alter its type

I have a table that looks like:
create_table "google_records", :force => true do |t|
t.string "user_id"
t.string "date"
t.text "stats"
t.text "account_name"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.float "total_cost", :limit => 12, :default => 0.0, :null => false
t.integer "total_conversions", :default => 0, :null => false
end
I need to be able to query the db using group like group('year(date)').group('month(date)') but can not do that because my column type is string for date.
Rather than change the column type to datetime through a migration (because there is a lot of code on prod that uses it as string), I was thinking about adding a new column.
Is there an way to populate that new column by duping the current date column and then calling something like date.to_datetime on each field?
Is there a better approach?
Yes, there's no reason why you can't create a field and (in the migration itself) put in some Ruby code to fix this on the 'up' migration
reversible do |dir|
dir.up { GoogleRecord.update_all_dates }
end
And define the :update_all_dates in the class to do just that.
You may also want to put a before_save callback in the Model so that every time a record is saved, new_date is updated with the value in date
class GoogleRecord < ActiveRecord::Base
before_save :update_date
def self.update_all_dates
all.each {|gr| gr.update_attribute(:new_date, Date.parse(gr.date)) }
end
private
def update_date
self.new_date = Date.parse(date)
end
strptime allows you to give a format and a string and it will output a datetime for you.
So create your new datetime column (in my example its :datetime_column), and then in your rails console
> all_records = GoogleRecord.all
> all_records.each {|r| r.update_attributes(datetime_column: Date.sprptime(r.date, "%Y-%m-%d"}
(or whatever your date format is in)
You might have to tool around with it as I haven't run any test cases, but let me know if there are any problems

Creating a table per account

I have an SMS gateway with a central price table referenced by all accounts. However, there is a requirement for unique prices for different routes for accounts.
I cannot serve this from the same price table. I was thinking of having a prices table for every account which is created automatically on account creation and specific pricing can be defined for specific account.
Any idea how i can implement this in Ruby on Rails? How can i make sweeping changes accross all tables?
The schema for table looks like this;
create_table "prices", :force => true do |t|
t.string "country"
t.string "network"
t.decimal "price_euros", :precision => 10, :scale => 3
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.decimal "price_ugx", :precision => 10, :scale => 3
t.decimal "price_kes", :precision => 10, :scale => 3
t.decimal "price_tzs", :precision => 10, :scale => 3
t.decimal "price_usd", :precision => 10, :scale => 3
end
Thank you

Ruby on Rails ActiveRecord Database Migration Failure

I have a preexisting sqlserver database 'MyDatabase' populated with data. Within this database I have two schemas, 'dbo' and 'Master'.
dbo is the default schema and contains tables:
OWNER
LOCATION
Master schema contains tables:
BANK
ZONE
Tables OWNER, LOCATION, BANK, and ZONE contain several attributes a piece.
I have initialized a RoR server and have verified that the appropriate gems are installed (activerecord, tiny_tds, activerecord-sqlserver-adapter), as well as that in database.yml the correct information is provided such that a connection can be established. I ~am~ able to connect to the database. I am able to add and remove tables.
The unusual thing to me is that when I run rake db:migrate, only attributes from the dbo schema become automatically initialized in the schema.rb file of my RoR server:
ActiveRecord::Schema.define(:version => 20131014210258) do
create_table "BANK", :id => false, :force => true do |t|
end
create_table "LOCATION", :id => false, :force => true do |t|
t.string "VarA", :limit => 50
t.string "VarB", :limit => 50
t.decimal "VarC", :precision => 28, :scale => 0
t.integer "VarD"
t.string "VarE", :limit => 500
end
create_table "OWNER", :id => false, :force => true do |t|
t.string "VarF", :limit => 50
t.string "VarG", :limit => 50
t.string "VarH", :limit => 50
t.string "VarI", :limit => 50
t.string "VarJ", :limit => 50
end
create_table "ZONE", :id => false, :force => true do |t|
end
end
Why is it that the attributes are not automatically populated for tables from my Master schema? I have significantly reduced the scope of my database for this question...in actuality there are dozens of tables with dozens of attributes per, so doing the work manually is really not an option.
Is there a way to assign a specific schema(s) towards which ActiveRecord will default to search and generate attributes for?
Help! & Thank you in advance!

How to specify "unique" values in Rails 3, PostgreSQL next to existing "unique key"?

I have existing Rails app written in Rails 3.2 and using PostgreSQL as db engine. Our products table holds products from several websites. Every product currently gets an unique id upon entry.
Here is the model :
class Platform < ActiveRecord::Base
attr_accessible :name, :url, :country, :email
validates :name, :presence => true,
:length => { :minimum => 1 }
has_many :sectors
end
and database schema for this table from schema.rb
create_table "platforms", :force => true do |t|
t.string "name"
t.string "url"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "country"
t.string "email"
end
Is it possible to add another "unique key" that would forbid entry or new products using the "URL" parameter? I am not sure hot to achieve such a thing with Rails g migration without damaging existing records (if duplicates already exist).
So basically : I want rails to forbid addition of a new product if the url of the new product corresponds to the url already in the database, similar as I am not allowed to enter product with id=1 if there is a product with id=1 in the database already.
You can do that on the model:
class MyModel < ActiveRecord::Base
validates_uniqueness_of :url
end
Or (depending on your DB, MySQL could react differently than PGsql):
# migration file
t.string :url, :null => false, :unique => true

Ruby on Rails: How do you seed the *_type column in polymorphic models?

I have a lot of data that I'm trying to seed into a polymorphic model in Rails 2.3.8. The association for all of the data is with the County model. The data looks like:
data = Datum.create([
...
{ :value => '14389', :value_type => County, :value_id =>'3103'},
{ :value => '59013', :value_type => County, :value_id =>'3105'},
{ :value => '17117', :value_type => County, :value_id =>'3106'},
...
])
The :value_type => County values lead to "undefined method `base_class' for String:Class."
I have tens of thousands of these values that I would like to seed into the database. They are similar to the values above except some are associated with the County model, some with the State model, and some with the City model. They are static values that will not be edited after seeding into the database.
How do I seed the model into the :value_type field?
(or... am I approaching this incorrectly and if so, how would you approach it?)
Edit: The relevant part of the schema.rb file:
Isaac -
create_table "data", :force => true do |t|
t.integer "value"
t.string "value_type"
t.integer "value_id"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "counties", :force => true do |t|
t.string "name"
t.integer "state_id"
t.integer "ansi_code"
t.string "ansi_class"
t.datetime "created_at"
t.datetime "updated_at"
end
I tried the following on the seeding, too, and it didn't work (County in quotes):
{ :value => '14389', :value_type => 'County', :value_id =>'3103'},
You definitely don't need the "value" column in your schema -- just "value_id" and "value_type". Then your seed data should look like this:
...
{ :value_id => 12345, :value_type => "County" },
...
Note that "County" is a string in quotes.
Another alternative would be to do this:
{ :value => County.find(12345) }
And then Rails will automatically set the :value_type and :value_id columns for you based on the class name and id of the County record. This example might give you a better idea of what's going on. However, for thousands of records this would be much slower, so the first approach is probably better for this case.
This is happening because you've done this in your model:
belongs_to :value, :polymorphic => true
And because you're trying to set the value column on the table too. Rails will not be able to tell the difference between you setting the association or the column via this method. To set the column use this:
self[:value] = "something"

Resources