Rails MySQL auto generated column - mysql

I am working on RoR 3.x with MySQL as backend.
Is there any way to modify the existing id (autogenerated with migration) in a way that can generate particular user defined pattern.
For e.g : "Products Table" should have values in "id" field like "P01", "P02" and so on, where P can be specified by the user, and 01,02 are autogenerated.
Thanks in advance!

The 'regular' IDs (1, 2, 3, ..., n) in this case aren't generated by rails but by MySQL (using AUTO_INCREMENT). So, if you want to go with auto-generated, auto-incrementing IDs, I would suggest not messing with this. What you could do, and what I would suggest, is creating an additional column and then populating that using a callback on your model.
Example:
class Product < ActiveRecord::Base
attr_accessor :user_supplied_prefix
after_create :generate_user_supplied_id
private
def generate_user_supplied_id
update_attribute(:user_supplied_id, "#{self.user_supplied_prefix}#{self.id}")
end
end
The downside of this approach is that Product.find(user_supplied_id) won't work. Fortunately, Product.find_by_user_supplied_id(user_supplied_id) will.

Related

Update column of another table from another table model rails

I have a table called Application and another table called Application_Case_Status
in my code, I create the applications and i want to update the application_case_status table column "application-source".
Upon creating an application, one of the column is :case_code ="OF-123" or "ON-123"
In my Application_case_Status table, i hv a column :loan_application_id and :application_source
My code in application.rb
after_create :generate_source_id
def generate_source_id
application_object = Application.find(self.id)
if application_object.case_code.include? "OF-"
update_attribute(:application_source, "Manual Upload")
end
if self.case_code.include? "ON-"
update_attribute(:application_source, "Website")
end
end
I get error that it cant find column :application_source how can i get it to update this column which is Application_Case_Status table
As per your code, it seems that it tries to update column of table Application but Application table doesn't have column named "application_source".
You need to update table Application_case_Status
First of all: You don't need application_object = Application.find(self.id) because self is the application_object already.
Furthermore, you have two if statements but it looks like they can't be both true at the same time so you should convert them to one if...else.
So, assuming:
class Application
has_one :application_case_status
end
class ApplicationCaseStatus
belongs_to :application
end
your method should look like this:
def generate_source_id
# we are going to check "case_code" **once** and feed the "application_source" variable
application_source =
if self.case_code.include? "OF-"
"Manual Upload"
else
"Website"
end
# and then we are going to create the "ApplicationCaseStatus" entity
ApplicationCaseStatus.create!(:application_id = self.id, :application_source, application_source)
end
Notice, as per #Tien Nguyen's remark, that we are creating an ApplicationCaseStatus entity because we have assumed it's not created already. If that's not the case, you should just update it (self.application_case_status.update_attribute!(:application_source, application_source))
Let me know if something doesn't work quite as you want it or doesn't make sense.

Storing list of actions in Rails app

I need some advice. I'm making an app that is a little complicated to learn. It has a user model. Once a user signs up, I'd like a modal dialog to appear the first time (and only the first time) he/she access certain pages. For example, there's a "vote" page and a "create a poll" page, etc.
What's the best way to implement this type of help system? I thought of adding a column to my user model that can contains a default list of values like "vote,create,share." When the user accesses the page that corresponds to one of those actions, if the name of the action is still in the list, the modal appears and the name of the action is removed from the list.
Does this sound reasonable? I know that in a normalized database, you shouldn't store multiple values in a single field. But it seems crazy to create a table called "actions" and another joining table to relate users to actions. There are only 4 or 5 things the user can do on the site.
Or is there some other way to do this that I'm missing? Thanks in advance for your advice.
You should probably make a UserTrigger model that can be used to "trigger" certain actions like this. It would look something like this in practice:
<% for_trigger(#user, :first_time_help) do %>
...help content...
<% end %>
This method would have a definition approximately like:
def for_trigger(model, name)
if (model.triggers.where(:name => name.to_s).delete_all > 0)
yield
end
end
A softer version would have a should_trigger? and did_trigger! method pair, where one would test and the other would actually remove the trigger record. This single-shot one should be good enough for most cases.
You would have a definition in your User model roughly like:
class User < ActiveRecord::Base
has_many :triggers,
:class_name => 'UserTrigger'
end
class UserTrigger < ActiveRecord::Base
belongs_to :user
end
You will have to pre-populate these trigger records after_create on your User model, or any other models that require it. To re-set the trigger, just re-add the record.

Rails / Active Record has_and_belongs_to_many association - fetching a record

I have two models User and Company associated by has_and_belongs_to_many.
I can fetch all users belonging to a certain company using
Company.find(id).users
The problem I've is finding all users that DO NOT belong to a certain company. Well, I could do that using
User.all - Company.find(id).users
But, I feel there's certainly a better way to achieve this. Is there an activerecord solution to this ?
Currently, I have 8 users (id from 1 to 8). When I try,
User.joins(:companies).where('companies.id = ?', 13).map(&:id)
I get result [7, 8] which is as expected. When I place != in the above query, the results are not what I want, i.e. array of 1 to 6.
Need help.
Thanks.
The easiest way might be with a class method... something like:
class User
has_and_belongs_to_many :companies
class << self
def exclude_company(company)
User.scoped.reject! {|u| u.companies.include? company}
end
end
end
Then in your code:
#company = Company.find(company_id)
#users = User.exclude_company(#company)
YMMV; I've done similar things in the past, but the above code is untested.
Also, if this is a common query pattern, you would probably be better served by the extensions to ARel provided in MetaWhere and its companion MetaSearch. N.B. These are replaced by new gems by the same author in Rails 3.1
Hope this helps.

Access SQL computed columns through ActiveRecord

I have a Person model, which includes a property representing the data of birth (birth_date).
I also have a method called age(), which works out the current age of the person.
I now have need to run queries based on the person's age, so I have replicated the logic of age() as a computed column in MySQL.
I cannot workout how I would make this additional column part of the default select statement of the model.
I would like to be able to access the age as if it were a native property of the Person model, to perform queries against it and access the value in my views.
Is this possible, or am barking up the wrong tree?
I thought I might be able to define additional fields through default_scope or scope, but these methods seem to only recognise existing fields. I also tried default_scope in tandem with attr_assessor.
Possible workarounds I've considered but would prefer not to do:
Create an actual property called age and populate through the use of callbacks. The date is always changing, so this obviously would be be reliable.
Replicate the logic in ActiveRecord as age() and in a scope as a where cause. This would achieve what I need, but doesn't feel very DRY.
I am already caching the results of the age() method. it is the ability to use the field in where clauses that I am most interested in.
There must be a way to define dynamic fields through SQL that I can access through the model by default.
Any help would be appreciated.
Rich
UPDATE
An example of my failed attempt to utilise scopes:
default_scope :select => "*, 2 as age"
attr_accessor :age
age is blank, I assume because scopes only deal with limiting, not extending.
kim3er your solution to your problem is simple. Follow these steps:
Loose the attr_accessor :age from your model. You simply don't need it.
Leave the default scope at the Person model: default_scope :select => "*, 2 as age"
Lastly open up a console and try
p = Person.first
p.age
=> 2
When you define a select using as, Rails will automagically add those methods on the instances for you! So the answer to your question:
There must be a way to define dynamic fields through SQL that I can access through the model by default.
is:
Rails
I'm not an expert by any stretch, but it seems you want:
class Person < ActiveRecord::Base
scope :exact_age, lambda { |a| where('age = ?', a) }
scope :age_gt, lambda { |a| where('age > ?', a) }
but that said, I've just started looking at Arel, seems pretty cool

Indexing calculated field for search conditions in Thinking Sphinx

I have a products model set up that I am trying to search with Thinking Sphinx. The model has an attribute called status which can be Active, Not active or Active during specified dates.
I would like to be able to restrict my search results to products that are active. I.e. has status of active or has status of active during dates and the current time is between those dates.
I'm a beginner to Rails so I'm looking for suggestions as to how I could implement this. I thought about putting a boolean method in my model that calculates this logic, but I don't think that this is indexable by Sphinx.
I am using MySQL as the database server.
Does anyone have any bright ideas?
You're right, ruby methods on your model are not accesible to sphinx. However you can re-create the method as a sphinx attribute. These can easily be made using SQL fragments like so:
class Person < ActiveRecord::base
...
define_index do
has "status = 'active' and now() > start_date and now() < end_date", :as => :active, :type => :boolean
end
...
end
Using a string to specify a field or attribute like this is the same as specifying a custom column when building an SQL query.
try the #indexes method (haven't tried myself, just noticed in googling around)
http://www.slideshare.net/sazwqa/using-thinking-sphinx-with-rails-presentation
slide 11
http://rdoc.info/rdoc/freelancing-god/thinking-sphinx/blob/04320b610b3a665ca1885cc2e6f29354d029e49a/ThinkingSphinx/Index/Builder.html#indexes-instance_method
Also:
http://www.mail-archive.com/rubyonrails-deployment#googlegroups.com/msg02046.html