Add custom columns to delayed_jobs table - ruby-on-rails-3

Can someone show me how to extend the delayed_jobs gem to allow me to add a couple custom columns?
I added a couple columns but when I try to 'cleanly' use them I get:
Can't mass-assign protected attributes: owner_type, owner_id
So I need to add the columns to cattr_accessor:
module Delayed
class Worker
DEFAULT_SLEEP_DELAY = 5
DEFAULT_MAX_ATTEMPTS = 25
DEFAULT_MAX_RUN_TIME = 4.hours
DEFAULT_DEFAULT_PRIORITY = 0
DEFAULT_DELAY_JOBS = true
DEFAULT_QUEUES = []
DEFAULT_READ_AHEAD = 5
cattr_accessor :min_priority, :max_priority, :max_attempts, :max_run_time,
:default_priority, :sleep_delay, :logger, :delay_jobs, :queues,
:read_ahead, :plugins, :destroy_failed_jobs, **:owner_id, :owner_type**
However, not sure the best way to extend this. My guess/attempt is to create a file and add it to the initializers directory. However, for some reason it didn't work.
Any tips appreciated.

Do you really need to extend the delayed_jobs table? My approach has been to leave it alone and use one of two techniques:
add owner_id and owner_type fields the the object being queued.
create a separate table with a :belongs_to relationship to delayed_jobs. Then you use DJ's hooks to keep the two in synch through the lifetime of the job.
The first approach is simpler, but isn't right for every situation. Would either of those work for you?

The other answers may be useful, but they are not answering the question. To add custom columns to the delayed_jobs table, you can follow this steps. I did so and successfully created an association between Delayed::Job and other objects.

Another option is to simply add the following line in your initializer (ex. config/initializers/delayed_job.rb):
Delayed::Job.attr_accessible :owner_type, :owner_id

Related

How can I get Rails 5 to play nicely with a primary key that has a period in it?

I'm working with a database I have no control over, and cannot make alterations to. This database has a table called warehouse_items. Each warehouse item is uniquely identified by a primary key indicating the item id.
Unfortunately, that primary key attribute is named WAREHOUSE_ITEM.ID
(Note the obnoxious period between "item" and "id")
When I try to run a basic query, such as:
WarehouseItem.find('wh3453')
I get an Undefined Table error.
Fortunately, when looking at what Rails is attempting to do, the problem becomes obvious:
: SELECT "warehouse_items".* FROM "warehouse_items" WHERE "WAREHOUSE_ITEM"."ID" = $1 LIMIT $2
Because of the period in the attribute name, Rails is treating "WAREHOUSE_ITEM.ID" as a table/attribute combination, rather than an attribute name with a period in it.
When I run the following PSQL query by hand, I get exactly what I need:
SELECT "warehouse_items".* FROM "warehouse_items" WHERE "warehouse_items"."WAREHOUSE_ITEM.ID" = 'wh3453'
Why is Rails screwing this up, and how can I fix it?
EDIT:
Also worth noting: I've tried using self.primary_key to override the primary key to no avail.
I've tried both a string and a symbol, as in:
self.primary_key="WAREHOUSE_ITEM.ID"
and
self.primary_key=:"WAREHOUSE_ITEM.ID"
Neither one has worked...
Thanks for all the help, everyone!
A suggestion in the comments to use find_by_sql does work! However, I stumbled onto a different solution that works even better.
First, I aliased the annoying attribute name to something simple: id
alias_attribute :id, :"WAREHOUSE_ITEM.ID"
Notice that it's still a symbol, which is important for the next step.
I then overwrite the primary_key method with a custom function:
def self.primary_key
return "id"
end
Now, when I do WarehouseItem.find('wh3453'), Rails defaults to checking id, which is aliased to the correct symbol and it works as intended!!!

Peoplesoft CreateRowset with related display record

According to the Peoplebook here, CreateRowset function has the parameters {FIELD.fieldname, RECORD.recname} which is used to specify the related display record.
I had tried to use it like the following (just for example):
&rs1 = CreateRowset(Record.User, Field.UserId, Record.UserName);
&rs1.Fill();
For &k = 1 To &rs1.ActiveRowCount
MessageBox(0, "", 999999, 99999, &rs1(&k).UserName.Name.Value);
End-for;
(Record.User contains only UserId(key), Password.
Record.UserName contains UserId(key), Name.)
I cannot get the Value of UserName.Name, do I misunderstand the usage of this parameter?
Fill is the problem. From the doco:
Note: Fill reads only the primary database record. It does not read
any related records, nor any subordinate rowset records.
Having said that, it is the only way I know to bulk-populate a standalone rowset from the database, so I can't easily see a use for the field in the rowset.
Simplest solution is just to create a view, but that gets old very soon if you have to do it a lot. Alternative is to just loop through the rowset yourself loading the related fields. Something like:
For &k = 1 To &rs1.ActiveRowCount
&rs1(&k).UserName.UserId.value = &rs1(&k).User.UserId.value;
&rs1(&k).UserName.SelectByKey();
End-for;

Trying to refactor Rails 4.2 scope

I have updated this question
I have the following SQL scope in a RAILS 4 app, it works, but has a couple of issues.
1) Its really RAW SQL and not the rails way
2) The string interpolation opens up risks with SQL injection
here is what I have:
scope :not_complete -> (user_id) { joins("WHERE id NOT IN
(SELECT modyule_id FROM completions WHERE user_id = #{user_id})")}
The relationship is many to many, using a join table called completions for matching id(s) on relationships between users and modyules.
any help with making this Rails(y) and how to set this up to take the arg of user_id with out the risk, so I can call it like:
Modyule.not_complete("1")
Thanks!
You should have added few info about the models and their assocciation, anyways here's my trial, might have some errors because I don't know if the assocciation is one to many or many to many.
scope :not_complete, lambda do |user_id|
joins(:completion).where.not( # or :completions ?
id: Completion.where(user_id: user_id).pluck(modyule_id)
)
end
PS: I turned it into multi line just for readability, you can change it back to a oneline if you like.

Magento Bulk update attributes

I am missing the SQL out of this to Bulk update attributes by SKU/UPC.
Running EE1.10 FYI
I have all the rest of the code working but I"m not sure the who/what/why of
actually updating our attributes, and haven't been able to find them, my logic
is
Open a CSV and grab all skus and associated attrib into a 2d array
Parse the SKU into an entity_id
Take the entity_id and the attribute and run updates until finished
Take the rest of the day of since its Friday
Here's my (almost finished) code, I would GREATLY appreciate some help.
/**
* FUNCTION: updateAttrib
*
* REQS: $db_magento
* Session resource
*
* REQS: entity_id
* Product entity value
*
* REQS: $attrib
* Attribute to alter
*
*/
See my response for working production code. Hope this helps someone in the Magento community.
While this may technically work, the code you have written is just about the last way you should do this.
In Magento, you really should be using the models provided by the code and not write database queries on your own.
In your case, if you need to update attributes for 1 or many products, there is a way for you to do that very quickly (and pretty safely).
If you look in: /app/code/core/Mage/Adminhtml/controllers/Catalog/Product/Action/AttributeController.php you will find that this controller is dedicated to updating multiple products quickly.
If you look in the saveAction() function you will find the following line of code:
Mage::getSingleton('catalog/product_action')
->updateAttributes($this->_getHelper()->getProductIds(), $attributesData, $storeId);
This code is responsible for updating all the product IDs you want, only the changed attributes for any single store at a time.
The first parameter is basically an array of Product IDs. If you only want to update a single product, just put it in an array.
The second parameter is an array that contains the attributes you want to update for the given products. For example if you wanted to update price to $10 and weight to 5, you would pass the following array:
array('price' => 10.00, 'weight' => 5)
Then finally, the third and final attribute is the store ID you want these updates to happen to. Most likely this number will either be 1 or 0.
I would play around with this function call and use this instead of writing and maintaining your own database queries.
General Update Query will be like:
UPDATE
catalog_product_entity_[backend_type] cpex
SET
cpex.value = ?
WHERE cpex.attribute_id = ?
AND cpex.entity_id = ?
In order to find the [backend_type] associated with the attribute:
SELECT
  backend_type
FROM
  eav_attribute
WHERE entity_type_id =
  (SELECT
    entity_type_id
  FROM
    eav_entity_type
  WHERE entity_type_code = 'catalog_product')
AND attribute_id = ?
You can get more info from the following blog article:
http://www.blog.magepsycho.com/magento-eav-structure-role-of-eav_attributes-backend_type-field/
Hope this helps you.

Rails 3 selecting only values

In rails 3, I would like to do the following:
SomeModel.where(:some_connection_id => anArrayOfIds).select("some_other_connection_id")
This works, but i get the following from the DB:
[{"some_other_connection_id":254},{"some_other_connection_id":315}]
Now, those id-s are the ones I need, but I am uncapable of making a query that only gives me the ids. I do not want to have to itterate over the resulst, only to get those numbers out. Are there any way for me to do this with something like :
SomeModel.where(:some_connection_id => anArrayOfIds).select("some_other_connection_id").values()
Or something of that nautre?
I have been trying with the ".select_values()" found at Git-hub, but it only returns "some_other_connection_id".
I am not an expert in rails, so this info might be helpful also:
The "SomeModel" is a connecting table, for a many-to-many relation in one of my other models. So, accually what I am trying to do is to, from the array of IDs, get all the entries from the other side of the connection. Basicly I have the source ids, and i want to get the data from the models with all the target ids. If there is a magic way of getting these without me having to do all the sql myself (with some help from active record) it would be really nice!
Thanks :)
Try pluck method
SomeModel.where(:some => condition).pluck("some_field")
it works like
SomeModel.where(:some => condition).select("some_field").map(&:some_field)
SomeModel.where(:some_connection_id => anArrayOfIds).select("some_other_connection_id").map &:some_other_connection_id
This is essentially a shorthand for:
results = SomeModel.where(:some_connection_id => anArrayOfIds).select("some_other_connection_id")
results.map {|row| row.some_other_connection_id}
Look at Array#map for details on map method.
Beware that there is no lazy loading here, as it iterates over the results, but it shouldn't be a problem, unless you want to add more constructs to you query or retrieve some associated objects(which should not be the case as you haven't got the ids for loading the associated objects).