Update column of another table from another table model rails - mysql

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.

Related

Generating an auto incrementing number in rails

I am very new to rails and was wondering if someone might be able to help me.
I need to generate and save an auto incrementing number for an invoicing. Ive already created the field 'invoicenum:integer' in my billing_history table.
I was wondering how I can do this from the controller ? This is the entry point where I was wanting to put it. Im not sure how I would write the function to create this incrementing number... Do i write it inside this function or do i create another function outside of this and just call it ?
transaction.company.billing_history.create!(
reference: transaction.description,
amount: transaction.amount,
plan: transaction.plan,
status: 'success',
invoicenum:
)
it's more preferable to make your controller slim so for a code like this its better to be on the model
lets say you have
BillingHistory.rb
you could set a callback to generate the invoice number like this
class BillingHistory < ApplicationRecord
before_create :generate_invoice_number
private
def generate_invoice_number
# logic for generating invoice number
# adjust accordingly to your needs
self.invoicenum = BillingHistory.maximum(:invoicenum).next
end
end
this will assign the value of BillingHistory.invoicenum before validated

How to use trim in select query rails or in sql query

User.select(:name).group(:name).having("count(*) > 1")
this query works fine to select records having duplicate user name. But problem am facing is when there is space in name.
For example.
recoed1 = "Username"
record2 = "Username "
This are the two records but they are having same name, but above query consider them as different records because space is there in the second record. So while selecting I did not get this record.
Any solution using normal mysql query or rails will do.
OR
How I can strip or trim all the column data first from table using rails/mysql query. Then I can apply above query.
What i would do here is make sure your data is tidy in the first place.
You could put in a pre-validation method to call strip on usernames. You could do it like so
#in lib/trimmer.rb
module Trimmer
# Make a class method available to define space-trimming behavior.
def self.included base
base.extend(ClassMethods)
end
module ClassMethods
# Register a before-validation handler for the given fields to
# trim leading and trailing spaces.
def trimmed_fields *field_list
before_validation do |model|
field_list.each do |field|
model.send("#{field}=", model.send("#{field}").strip) if model.send("#{field}").respond_to?('strip')
end
end
end
end
end
Make sure this module is required, wherever you require things in lib in your config.
Now, you can say, in any models, like so (in this example i'm doing some other fields besides username)
class User < ActiveRecord::Base
include Trimmer
trimmed_fields :username, :email, :first_name, :last_name
...
So, that will fix you going forward. The remaining step is to tidy up your existing data. I would do this in a migration. (again, i'm doing some other fields as an example)
tables_and_cols = {"users" => %w(username email first_name last_name), "foos" => %w(bar baz)}
tables_and_cols.each do |table, cols|
cols.each do |col|
ActiveRecord::Base.connection.execute("update #{tablename} set #{col} = trim(#{col})")
end
end
Now, after doing this trim, you may have some duplicate usernames. You will need to decide how you are going to deal with that, since the records involved are no longer valid. If you haven't publically deployed this yet, ie if you don't have any active real users, then it doesn't matter: you can change the usernames to something else. But if you do have real people using it you will probably need to change the username for some of them and inform them. This is unavoidable if you want to maintain a situation where people can't have spaces at the start or end of their username.
You can use mysql's string functions:
User.select("lower(trim(name))").group("lower(trim(name))").having("count(*) > 1")

What is the best way to merge 2 tables with Active Record and Mysql

We need to allow users to customize their entities like products... so my intention was to have a product table and a custom_product table with just the information the users are allowed to change.
When a client goes to the product I want to merge the information, means I want to merge the two tables - the custom overwrites the default Products table.
I know that in mysql there exists a ifnull(a.title, b.title) way but I was wondering if there is any nice and efficient way to solve this in Rails 4 with Active Record. Assume that the products and custom products table have just 2 columns, ID and TITLE
I think you can convert both objects to JSON and then handle their params as a hash, using the merge method:
class Product
end
class Customization
belongs_to :product
end
a = Product.find(...)
b = a.customization
c = JSON(a.to_json).merge(JSON(b.to_json).reject!{|k,v| v.nil?})
Therefore c will contain all params from Product eventually overridden by those in Customization which are not nil.
If you still want to use a Product object with hybrid values (taken from Customization) you can try this:
a.attributes = a.attributes.merge(b.attributes.reject!{|k,v| v.nil?})
In this case a will still be a Product instance. I would recommend to keep the same attributes in both models when doing this.

Rails MySQL auto generated column

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.

How to update existing record if the one being saved has the same key?

MySQL has a very nice option for INSERT statement, which is particularly helpful for join tables without the id column. It inserts a record, but, instead of throwing an error if its key clashed with the existing one, that record is updated. Here's an example:
INSERT INTO table (key1,key2,data) VALUES (1,2,3)
ON DUPLICATE KEY UPDATE data=3;
How to achieve the same with Active Record? The resultant code would then look like this:
class Model < ActiveRecord::Base
belongs_to :key1
belongs_to :key2
end
record = Model.new
record.key1 = key1
record.key2 = key2
record.data = 'new data'
record.WHAT? #Inserts or updates `data` for the existing record
The answer by j is the right idea, but you probably want to go with find_or_initialize_by to avoid multiple saves on the object. E.g.
record = Model.find_or_initialize_by_key1_and_key2 new
record.data = 'new data'
record.save
By the sounds of it, you also want a validation to check that the model doesn't allow duplicate joins too:
class Model < ActiveRecord::Base
belongs_to :key1
belongs_to :key2
validates_uniqueness_of :key1, :scope => :key2
end
You can do the following:
record = Model.find_or_create_by_key1_and_key2(:key1 => key1, :key2 => key2)
record.update_attribute(:data, "new data")
EDIT
zaius idea looks better, you should use find_or_initialize_by to avoid multiple saves, as he said :]
You may want to take a look at composite primary keys. It's a plugin for ActiveRecord.
First of that's a MySQL-specific solution, as far as I know that syntax doesn't work with any other SQL-servers. Usually called Upsert in discussions.
I'd go with making a new method called save_or_update and then if the save fails, with a duplicate key exception, load and update_params.