I am struggling with an issue with a Rails 5.2.4.1 app.
Configuration is the following:
Ruby 2.6.5
Rails 5.2.4.1
attr_encrypted 3.1.0
I have a model called Chicken that has 2 attributes: name - which is attr_encrypted and number - which is a normal integer field. Whenever I perform queries to retrieve any other fields except the attr_encrypted one, that still gets attached to the result and it's alway nil:
Chicken.select(:number) => #<ActiveRecord::Relation [#<Chicken id: nil, number: nil, name: nil>]>
Please keep in mind that this is just a test application and the queries that I am trying to execute on the actual app where I have encountered this initially, are more complex.
Is there a way to prevent attr_encrypted from attaching encrypted fields to queries results? Since the current results mean that I have to re-write all the existing queries in the app or add a filter for these types of fields somehow
This problem was caused by this change to attr_encrypted. As far as I can tell, there isn't any easy way to remove this attribute without modifications to the library but no one actively works on it so that seems unlikely.
The only options as far as I can see are to:
Use another library
Override the models attributes method to exclude the value (may produce undesirable results). It will still show in other methods active record provides.
Deal with it
Something else I haven't been able to find
A few ways you can deal with it:
Use a library to generate JSON responses for the frontend to only include attributes you want
redefine serializable_hash like devise does to remove attributes. (A lot safer than redefining the attributes method itself.
Related
I'm using the active_model_serializers gem for a RoR API. Versions:
Rails: 4.2.8
Ruby: 2.2.5
active_model_serializers: 0.10.0
I'm using a virtual attribute in a serializer. I get it by using a sub query when I retrieve the objects from the database.
You can find the code here: Github Gist
This is the error I'm getting:
undefined method 'number_of_reservations' for DiscountSchedule...
This field isn't defined in the table nor in the model (attr_accessor)
I'm not sure why it doesn't work, I have a very similar serializer and it's working OK.
Any help will be appreciated.
EDIT:
I have another serializer where the virtual/calculated field is working OK. My guess on this is that since AR is making a bunch of LEFT OUTER JOINS and the SELECT list of the query is very big at some point something is getting broke.
The link won't work for me as I don't have access at my work place, however, from the error I can recommend you to check if you have defined the attributes like this in your serializer attributes :number_of_reservations and have an action in the serializer that says
def number_of_reservations
// Your logic goes here.
end
I suspect this question has to be about ActiveRecord, rather than AMS. You're trying to use select and alias to collect some computed (aggregate) attribute along with objects themselves. This, unfortunately, won't work in ActiveRecord, at least not in versions below 4.2.X. And this is why you're observing this behavior, there is no number_of_reservations in your models.
To see what's going on, try to inspect #objects here: https://gist.github.com/LuisDeHaro/ebf92781b449aa1ee7b85f8f552dd672#file-some_controller-rb-L17
Indeed: the issue was by the big amount of LEFT JOINS that the includes(:table_name) is generating. The serializer then does not know what to do.
I found a monkey-patch gem that works for AR (Rails 4 & 5) that fix this.
https://github.com/alekseyl/rails_select_on_includes
So, the virtual field number_of_reservations is picked up by the serializer like a charm.
And, you might be wondering: why do you want to retrieve a field that is not in the table definition in the database. A: well, in some scenarios you will need a calculated field for EVERY row you are retrieving. A SQL sub query is one of the most efficient ways to do so.
It's working now for me.
This is closely related to Rails ignores columns from second table when using .select, however that question doesn't go deep enough.
As per the above question, I have a complex query being run from one of my ActiveRecord Models which generates a kind of 'report'. It is basically a giant table of the primary Model's attributes as well as a few other attributes from related tables.
The query itself, works. I have verified that the resulting SQL executes correctly and when pasted into a SQL terminal I get the results (and columns I want). Unfortunately there is proprietary information in the models that I can't share here, and the Query is too complex to obfuscate. But To give an idea of what I am doing, this is the start of my ActiveRecord Query: permits = Permit.select('*').joins("LEFT JOIN crosstab (' ....
I have pasted the ActiveRecord Query (above) into the Rails console and not only does it execute perfectly; but the additional attributes (not asssigned to any model or association in my app) can be queried, just fine - exactly what I want:
>> permits.first.applicant_name
"Gordon Ramsay"
The problem is that when I execute the code in the rails app (executed from the browser) I can access the attributes of each permit and its associated models ok, but the additional selects on permit raise a NoMethodError.
I cannot understand why the Rails console will let me plug the commands in and work, but when I run the same code in only of my application's methods, it raises an error.
The question above seems to deal with this closely, and the accepted answer suggests trying something out in the console; but why would the console and the Rails app itself deal with this same code differently (since I am under the assumption that the Rails console is an instance of the Rails application?
Does anyone know:
Is my assumption about the ActiveRecordRelation omitting the non-model attributes correct?
Why does the Rails console allow me to do this query and call the 'extra' selected columns but Rails will not.
Is there a way I can do what I need to do - perhaps creating a proxy object or casting the Permit model to some other ActiveRecord Object that doesn't 'ignore/drop' the extra attributes from the select?
I'm using Mongoid in a Rails project (both 4.0.x), and I've got a document with a hash field that stores some schema-less data.
class Thing
field :name, type: String
field :mass, type: Integer
field :info, type: Hash
end
With this setup, I can query for things, say, that have a key :endDate like so:
Thing.where("info.endDate"=>{'$exists'=>true})
And that's all nice and handy. Using a hash field for this :info field is nice because what I want to store doesn't have a fixed schema and varies from one thing to another.
Ok, but, I can't use the same dot syntax to $set key/value pairs in the :info hash. [1]
thing.set("info.endDate"=>Time.now)
Raises a Mongoid::Errors::UnknownAttribute error.
It tells me I'd have to include Mongoid::Attributes::Dynamic in my model to do this, but that doesn't seem right to me. The point of the hash field type seems to be to allow you to work with data that doesn't have a fixed schema. It doesn't seem like I should have to include a special "dynamic attributes" module to use hash fields.
So right now, I'm updating values using regular old [] syntax, and then calling save on the model, like so:
thing.info[:endDate] = Time.now
thing.save
But a lot of the time it happens that it would be nicer to just $set the value. Is there some other syntax for setting hash field values? Am I wrong about the above error message and Dynamic Attributes being wrong-headed? Am I stuck doing two step updates to hash fields for now?
[1] admittedly, I've recently migrated from mongomapper, and so my expectations of this syntax are partly set by having been able to do this previously in mongomapper.
The thing with Hash field is, it can be dynamic as much as you want. Therefore to prevent polluting your DB schema with unintended fields caused by bugs in your code this functionality is disabled by default.
No you are not stuck using 2-step updates for your hashes at all!
[],[]= are the shortcuts for read_attribute() and write_attribute() and should be used if you don't include Mongoid::Attributes::Dynamic. If you try to use $set without enabling dynamic attributes you will get a no-method error because it does not see your dynamic attributes as defined attributes.
If you'll read the source of Mongoid::Attributes::Dynamic then you'd find that this is required to add the dynamic attributes functionality.
To update the values by including Mongoid::Attributes::Dynamic you need to follow these steps:
thing = Thing.first
thing.set("info.endDate" => Time.now)
thing.reload # This will update the current variable
Otherwise if you need you can easily skip this and do the value update by 2-step method
I hope this sheds some light over your query.
Source:
Rails mongoid dynamic fields - no method error
Dynamic attributes with Rails and Mongoid
I think you pass parameter in wrong way. Replace arrow symbol with comma
You can change to this and it will work
thing.set("info.endDate", Time.now)
In Mongoid 3.0.21, how to get all model's attributes as a plain Ruby Hash?
Calling either #attributes or #raw_attributes returns Moped::BSON::Document. While it actually extends Hash, several hash method does not work as expected. Particularly #except returns unmodified self, not hash with given keys stripped off.
Update: Moped::BSON::Document properly inherits behavior of Hash. I was trying to name attributes with symbols, not strings, that's why #except didn't work. Shortly: do except('pictures'), not except(:pictures).
Hash[e.attributes]
where e is your model instance
I apologize for bumping something so old, but I wanted to leave this here for myself and all the future people who run into this same issue. I am using the Mongoid ORM for Rails, which uses Moped internally for its interaction with MongoDB.
This gem has now saved me hours and hours of manually converting things to Hash or HashWithIndifferentAccess: https://github.com/mindscratch/mongoid-indifferent-access.
Essentially it seems to have some sort of pre-return hook that automatically converts all documents coming from MongoDB to type HashWithIndifferentAccess.
Not looking for points on this. Just wanted to leave this here because it is the top Google result for this issue and it saved me from going insane.
i am having an issue with updating existing documents composite key fields in rails. the associated mongo query for my update_attributes statement seems to be correct, however the object cannot be found afterwards.
for example with an existing object with first_name "Jane" and last_name "Doe"... with my :key being :first_name, :last_name
i hit my update method with:
{"artist"=>{"last_name"=>"Doe", "first_name"=>"John"}, "commit"=>"Update Artist", "id"=>"jane-doe"}
def update
#artist = Artist.find(params[:id])
if #artist.update_attributes(params[:artist])
redirect_to #artist
end
end
which generates the mongo query: MONGODB app_database['artists'].update({"_id"=>"jane-doe"}, {"$set"=>{"_id"=>"john-doe", "first_name"=>"John"}})
which seems correct to me... but when i am redirected to that new artist, it complains about Document not found for class Artist with id(s) john-doe.
and in fact looking at my db from the mongo console, i still see Jane Doe in there. It is something to do with them being composite key fields, since i can update non-key fields just fine.
what am i missing here?
I tried this in an app of my own, and it looks like MongoDB simply doesn't currently allow you to modify the _id field as part of a $set operation (which is what Mongoid uses to perform updates). This is a strange restriction - I've been using Mongo for a year and a half now and I've never run into it.
So, a few options:
Stop using anything for your _id that might need to be changed later. I'd do this - it's a best practice anyway.
Whenever you need to make one of these _id changes, instead create a new record with the new _id attribute and delete the old one. This might get messy though, especially if you have other models that refer your Artist models by id.
File an issue with 10gen asking for this restriction to be lifted. They're very good about responding to users' concerns, but even if they agree, it'll probably take a while to be done.
File an issue with Mongoid to request support for these types of changes (Mongoid could conceivably handle the create + delete mechanism for you), but honestly, it's the kind of edge case that's probably not worth the extra time and code for them to support. It'd be nice if Mongoid raised an error when you tried to do an update like this, at the very least.