Rails ActiveRecord::Relation object using including models - sql

I need to retrieve information from two separate models which are similar but not the same. I am trying to do things like
I have looked into a few methods however they return an array of active objects rather than an
ActiveRecord::Relation which is required for many of the features of my app to work.
Is there any way to return an ActiveRecord::Relation object containing a union of both tables?
I have tried things like
#group = Mymodel.find_by_sql("SELECT id FROM Mymodels
UNION SELECT id FROM AnotherModels")
and also explored using the Model.where method however cannot return an ActiveRecord::Relation
EDIT:
Just to be clear I need to return ActiveRecord::Relation that is a union or a merge of the two tables

Have you tried MyFirstModel.joins(:my_second_models)? Check out details joins in the API here.
EDIT: Single Table Inheritance is a better solution to this problem. See comments below.

Try something like this:
Model.joins(:other_model).where("attr1" = :attr1,
{ attr1: "example" }).group(:attr1)
Since you commented about where, I added the where method on the call. You can also group everything using :group in the end.

Related

How do I implement, for instance, "group membership" many-to-many in Parse.com REST Cloud Code?

A user can create groups
A group had to have created by a user
A user can belong to multiple groups
A group can have multiple users
I have something like the following:
Parse.Cloud.afterSave('Group', function(request) {
var creator = request.user;
var group = request.object;
var wasGroupCreated = group.existed;
if(wasGroupCreated) {
var hasCreatedRelation = creator.relation('hasCreated');
hasCreatedRelation.add(group);
var isAMemberOfRelation = creator.relation('isMemberOf');
isAMemberOfRelation.add(group);
creator.save();
}
});
Now when I GET user/me with include=isMemberOf,hasCreated, it returns me the user object but with the following:
hasCreated: {
__type: "Relation"
className: "Group"
},
isMemberOf: {
__type: "Relation"
className: "Group"
}
I'd like to have the group objects included in say, 'hasCreated' and 'isMemberOf' arrays. How do I pull that using the REST API?
More in general though, am I approaching this the right way? Thoughts? Help is much appreciated!
First off, existed is a function that returns true or false (in your case the wasGroupCreated variable is always going to be a reference to the function and will tis always evaluate to true). It probably isn't going to return what you expect anyway if you were using it correctly.
I think what you want is the isNew() function, though I would test if this works in the Parse.Cloud.afterSave() method as I haven't tried it there.
As for the second part of your question, you seem to want to use your Relations like Arrays. If you used an array instead (and the size was small enough), then you could just include the Group objects in the query (add include parameter set to isMemberOf for example in your REST query).
If you do want to stick to Relations, realise that you'll need to read up more in the documentation. In particular you'll need to query the Group object using a where expression that has a $relatedTo pointer for the user. To query in this manner, you will probably need a members property on the Group that is a relation to Users.
Something like this in your REST query might work (replace the objectId with the right User of course):
where={"$relatedTo":{"object":{"__type":"Pointer","className":"_User","objectId":"8TOXdXf3tz"},"key":"members"}}

how to access column value after serialization activerecord

I have a simple model like this:
class User < ActiveRecord::Base
serialize :preferences
end
I want to access the raw value from mysql, not value before serialize. Is it possible?
I know I can use
ActiveRecord::Base.connection.execute("select * from users")
But I want to access from the User model.
Updated
Ok, this is what you are looking for:
User.find(params[:id]).attributes_before_type_cast["preferences"][:value]
This will return the string in its serialized form.
That is the closest you can get that I can find, it won't work if you have already gotten the object pulled from the database.
Sorry for misreading your question. You can use this from the User model too.
Leaving the old answer up just in case the other way of doing it is helpful to someone.
Old Answer
Just to be sure I understand the question, you want the raw data from the table. The data that rails serializes and puts in the database.
EX. You put in ['site_id','last_update','last_restart'] and you get "---\n- site_id\n- last_update\n- last_restart\n" and it is put in the database and saved. You want to retrieve this: "---\n- site_id\n- last_update\n- last_restart\n" from the database.
Ok, it took some fanagaling from the database but you can do it like so.
In a project I have a serialized array call devise_table_preferences that lists the preferences to display in a table in a particular order, like so:
user.devise_table_preferences = ['site_id','last_update','last_restart']
The serialized view of it is like so:
"---\n- site_id\n- last_update\n- last_restart\n"
Using your method above, I made a query like so:
preference = ActiveRecord::Base.connection.execute("SELECT devise_table_preferences FROM users WHERE id = #{#user.id}")
It returns an object in the console like so:
preference = #<Mysql2::Result:0x007fe4cdf34850>
Running:
preference.first[0]
Gave me this:
"---\n- site_id\n- last_restart\n"
I know its a big work around but it will definitely give you your data in its serialized way. Hope that it helps you out.
attributes_before_type_cast didn't work for me.
User.first.instance_variable_get(:#attributes)['preferences'].serialized_value
This works even if the object is loaded.
I think these days you want to say the following:
User.find(params[:id]).typecasted_attribute_value('preferences')

Can anyone explain how CDbCriteria->scopes works?

I've just checked the man page of CDbCriteria, but there is not enough info about it.
This property is available since v1.1.7 and I couldn't find any help for it.
Is it for dynamically changing Model->scopes "on-the-fly"?
Scopes are an easy way to create simple filters by default. With a scope you can sort your results by specific columns automatically, limit the results, apply conditions, etc. In the links provided by #ldg there's a big example of how cool they are:
$posts=Post::model()->published()->recently()->findAll();
Somebody is retrieving all the recently published posts in one single line. They are easier to maintain than inline conditions (for example Post::model()->findAll('status=1')) and are encapsulated inside each model, which means big transparency and ease of use.
Plus, you can create your own parameter based scopes like this:
public function last($amount)
{
$this->getDbCriteria()->mergeWith(array(
'order' => 't.create_time DESC',
'limit' => $amount,
));
return $this;
}
Adding something like this into a Model will let you choose the amount of objects you want to retrieve from the database (sorted by its create time).
By returning the object itself you allow method chaining.
Here's an example:
$last3posts=Post::model()->last(3)->findAll();
Gets the last 3 items. Of course you can expand the example to almost any property in the database. Cheers
Yes, scopes can be used to change the attributes of CDbCriteria with pre-built conditions and can also be passed parameters. Before 1.1.7 you could use them in a model() query and can be chained together. See:
http://www.yiiframework.com/doc/guide/1.1/en/database.ar#named-scopes
Since 1.1.7, you can also use scopes as a CDbCriteria property.
See: http://www.yiiframework.com/doc/guide/1.1/en/database.arr#relational-query-with-named-scopes

Rails: Load just one attribute not a whole model

Lets say I have a model, Foo, which is big and has lots of components. For a given Ajax query I'm only interested in one particular attribute, bar, which is a column in the foos table.
Is there a simple way I could load just that attribute, and not bother with retrieving the rest of the record? For instance if all I want to know is the bar for Foo with id#__, how could I retrieve that?
You can return only specific columns by calling the select method with a string containing the attributes you want to return. For your example:
Foo.select('bar').first #<Foo bar: 1>
Keep in mind that these objects will act like normal ActiveRecord objects but return nil for any field you did not select, so take care using this functionality.
You can call select on the class name itself or any Relation, so you can chain together the ActiveRecord calls you usually use like where, etc.
I prefer this
User.where(:id => user_id).pluck(:user_name).first #'tom'
Foo.where(:age => 23).pluck(:user_name) #['tom', 'jerry', ...]
Foo.where(<condition>).select('fieldname')
Example
results = Foo.where('is_active = ?', true).select('bar')
Access the selected fields as:
results.map {|res| res.bar} returns an array of bar's
pluck(*column_names)
doc: http://api.rubyonrails.org/classes/ActiveRecord/Calculations.html#method-i-pluck
e.g. Foo.pluck(:bar)
pick(*column_names) select just one top row's columns, docs
Similar to pluck but fetch only one row

Django queryset with "isnull" argument returning duplicates

I want to only return items that don't have associated images. My relationship is something like this:
class Post(models.Model):
....fields
class Photo(models.Model):
post=models.ForeignKey(Post,blank=True,null=True)
photo=models.FileField(upload_to="pics")
def __unicode__(self):
return str(self.post)
I put together the following query to return Post instances where Photo is not null:
posts=Post.objects.filter(photo__photo__isnull=False)
The problem is that it's returning multiple copies of each Post instance per the number of Photo instances that are related to the Post instance. In other words, one post has 5 photos and it is therefore returning five copies in the queryset. I've looked through the documentation and this is a bit tricky. I ended up using distinct(), but I assume that I can make it work immediately.
Thanks
To return posts that don't have associated photos, use the following query:
posts=Post.objects.filter(photo__isnull=True)
Later in your question you are using isnull=False. As you say, the resulting queryset will return each post once for every photo which is attached to it. To only include each post once in the queryset, use distinct.
posts=Post.objects.filter(photo__isnull=False).distinct()
I'm not sure why you query photo__photo__isnull in you're query -- My answer assumes you should use photo__isnull.
I'm not sure what you mean by "but I assume that I can make it work immediately", but using either distinct(), or order_by() should be the solution to your problem.