How should I merge hash while using 'first_or_create' - ruby

I have this hash, which is built dynamically:
additional_values = {"grouping_id"=>1}
I want to merge it with this record object after creation via first_or_create:
result = model.where(name: 'test').first_or_create do |record|
# I'm trying to merge any record attributes that exist in my hash:
record.attributes.merge(additional_values)
# This works, but it sucks:
# record.grouping_id = data['grouping_id'] if model.name == 'Grouping'
end
#Not working:
#result.attributes>>{"id"=>1, "name"=>"Test", "grouping_id"=>nil}
I understand that if the record already exists (returned via 'first'), it won't be updated...although that would be a nice option and any recommendations on that are welcome, but the table was just dropped and recreated, so that's not the issue.
What am I missing?
I also tried using to_sym, resulting with:
additional_values = {:grouping_id=>1}
...just in case there was some weirdness I didn't know about...didn't make a difference

The problem is Hash#merge returns a new hash and then you aren't doing anything with that hash, you're just throwing it away. I would also suggest sticking to using the ActiveRecord methods for updating attributes, instead of trying to manipulate the underlying hash, such as using assign_attributes or, if you want to save the record update. Though, you may find the create_with, which can be used with find_or_create_by, useful here:
model.create_with(additional_values).find_or_create_by(name: 'test')
I can't find any documentation that I like (if at all) for first_or_create in recent rails versions, but if you like that more than find_or_create_by, then if we look at the Rails 3 documentation for first_or_create, you should be able to do with out the create_with:
model.where(name: 'test').first_or_create(additional_attributes)

Related

ActiveStorage::Attachment find resource by blob_id

I have the following model
class Document
has_many_attached :previews
...
end
And I'm trying to find single elements there.
The problem is if I do:
#document.previews.find_by(blob_id: 22)
I get this error: undefined method `find_by' for #<ActiveStorage::Attached::Many>
So I'm kind of forced to loop through enumerable:
#document.previews.find { |p| p.blob_id == 22 }
Is there any other (better/prettier) way to do this?
#ntonnelier I have a similar model, and with Rails 7.0.3 your first example works fine for me:
#document.previews.find_by(blob_id: 22)
Another couple of options that work are:
#document.previews.where(blob_id: 22)
#document.previews.blobs.find_by_id(22)
You should be able to access the blobs for a particular record via the blobs method, which gets you an ActiveRecord collection, and you can use find on that one.
Something like #document.previews.blobs.find(22) might work in your particular case.

Rails 4: alternative for ActiveRecord 'all' as it is now deprecated

Is find_each an acceptable replacement for the ActiveRecord function all in version 4.0.0 of ActiveRecord?
For example, previously I had:
all_users = User.all
which produces a warning stating something along the lines of ActiveRelation:all is deprecated.
As a replacement I came up with:
User.find_each do |user|
all_users += user
end
Is this acceptable, or should I be doing it another way?
I understand the reason behind using find_each is because of 'batching' which will allow the query to stop running if there is a very large dataset. Let's assume for this case that the dataset is small.
EDIT
It seems the deprecation error only comes up when you use conditons, eg:
User.all(:conditions => ["name like ?", "%bob%"])
produces:
DEPRECATION WARNING: Relation#all is deprecated. If you want to
eager-load a rel ation, you can call #load (e.g.
Post.where(published: true).load). If you want to get an array of
records from a relation, you can call #to_a (e.g. Post.wher
e(published: true).to_a). (called from irb_binding at (irb):8)
The correct replacement for the above appears to be:
User.where("name like ?", "%bob%")
Model.all isn't deprecated in Rails 4, but it has changed. Instead of returning an array of all of the records, it returns an ActiveRecord Relation which is significantly faster.
Model.all is designed to deprecate Model.scoped which previously lazy loaded the records. Model.all can now be used for easier chaining of methods instead of scoped.
You can read all about it here in this article.

PageObject with Ruby - set text in a text field only works in the main file

I'm automating a site that has a page with a list of options selected by a radio button. When selecting one of the radios, a text field and a select list are presented.
I created a file (test_contracting.rb) that is the one through which I execute the test (ruby test_contracting.rb) and some other classes to represent my page.
On my class ContractPage, I have the following element declaration:
checkbox(:option_sub_domain, :id => "option_sub_domain")
text_field(:domain, :id => "domain_text")
select_list(:tld, :id => "domain_tld")
I've created in the ContractPage a method that sets the configuration of the domain like this:
def configure_domain(config={})
check_option_sub_domain
domain = config[:domain]
tld = config[:tld]
end
When I call the method configure_domain from the test_contracting.rb, it selects the radio button, but it doesn't fill the field with the values. The params are getting into the method correctly. I've checked it using "puts". Even if I change the params to a general string like "bla" it doesnt work. The annoying point is that if on test_contracting.rb I call the exact same components, it works.
my_page_instance = ContractPage.new(browser)
my_page_instance.domain = "bla"
my_page_instance.tld = ".com"
What I found to work was to in the configure_domain method, implement the following:
domain_element.value = config[:domain]
tld_element.send_keys config[:locaweb_domain]
Then it worked.
The documentation for the PageObjects module that I'm using as reference can be found here: http://rubydoc.info/github/cheezy/page-object/master/PageObject/Accessors#select_list-instance_method
Do you guys have any explation on why the method auto generated by the pageobject to set the value of the object didnt work in this scope/context ?
By the way, a friend tried the same thing with Java and it failed as well.
In ruby all equals methods (methods that end with the = sign) need to have a receiver. Let me show you some code that will demonstrate why. Here is the code that sets a local variable to a value:
domain = "blah"
and here is the code that calls the domain= method:
domain = "blah"
In order for ruby to know that you are calling a method instead of setting a local variable you need to add a receiver. Simply change your method above to this and it will work:
def configure_domain(config={})
check_option_sub_domain
self.domain = config[:domain]
self.tld = config[:tld]
end
I'm pretty new to this world of Selenium and page objects but maybe one of my very recent discoveries might help you.
I found that that assignment methods for the select_list fields only worked for me once I started using "self" in front. This is what I have used to access it within my page object code. e.g., self.my_select_list="my select list value"
Another note - The send_keys workaround you mention is clever and might do the trick for a number of uses, but in my case the select list values are variable and may have several options starting with the same letter.
I hope something in here is useful to you.
UPDATE (Jan 3/12)
On diving further into the actual Ruby code for the page object I discovered that the select_list set is also using send_keys, so in actuality I still have the same limitation here as the one I noted using the send_keys workaround directly. sigh So much to learn, so little time!

recreate_versions! using the unique filename method stated in the wiki

I'm trying to use the method recreate_versions! but I'm using the method from the wiki to create unique filenames. The problem is that when I run recreate_versions! it changes the filenames but it doesn't update them on the mounted object itself. How could I refresh these URL's?
A solution that works when dealing with caching is to save the mounted object after recreating versions:
Example:
avatar.image.recreate_versions!
avatar.save!
This way you can keep using unique filenames even when recreating versions and properly handle caching.
Here is what worked for me. It uses the filename if it already exists. So they don't change when you recreate_versions!
def filename
if original_filename
if model && model.read_attribute(:avatar).present? #or whatever you call your column
model.read_attribute(:avatar)
else
# create new filename however you're doing it
end
end
end

How to fire raw MongoDB queries directly in Ruby

Is there any way that I can fire a raw mongo query directly in Ruby instead of converting them to the native Ruby objects?
I went through Ruby Mongo Tutorial, but I cannot find such a method anywhere.
If it were mysql, I would have fired a query something like this.
ActiveRecord::Base.connection.execute("Select * from foo")
My mongo query is a bit large and it is properly executing in the MongoDB console. What I want is to directly execute the same inside Ruby code.
Here's a (possibly) better mini-tutorial on how to get directly into the guts of your MongoDB. This might not solve your specific problem but it should get you as far as the MongoDB version of SELECT * FROM table.
First of all, you'll want a Mongo::Connection object. If
you're using MongoMapper then you can call the connection
class method on any of your MongoMapper models to get a connection
or ask MongoMapper for it directly:
connection = YourMongoModel.connection
connection = MongoMapper.connection
Otherwise I guess you'd use the from_uri constructor to build
your own connection.
Then you need to get your hands on a database, you can do this
using the array access notation, the db method, or get
the current one straight from MongoMapper:
db = connection['database_name'] # This does not support options.
db = connection.db('database_name') # This does support options.
db = MongoMapper.database # This should be configured like
# the rest of your app.
Now you have a nice shiny Mongo::DB instance in your hands.
But, you probably want a Collection to do anything interesting
and you can get that using either array access notation or the
collection method:
collection = db['collection_name']
collection = db.collection('collection_name')
Now you have something that behaves sort of like an SQL table so
you can count how many things it has or query it using find:
cursor = collection.find(:key => 'value')
cursor = collection.find({:key => 'value'}, :fields => ['just', 'these', 'fields'])
# etc.
And now you have what you're really after: a hot out of the oven Mongo::Cursor
that points at the data you're interested in. Mongo::Cursor is
an Enumerable so you have access to all your usual iterating
friends such as each, first, map, and one of my personal
favorites, each_with_object:
a = cursor.each_with_object([]) { |x, a| a.push(mangle(x)) }
There are also command and eval methods on Mongo::DB that might do what you want.
In case you are using mongoid you will find the answer to your question here.
If you're using Mongoid 3, it provides easy access to its MongoDB driver: Moped. Here's an example of accessing some raw data without using Models to access the data:
db = Mongoid::Sessions.default
# inserting a new document
collection = db[:collection_name]
collection.insert(name: 'my new document')
# finding a document
doc = collection.find(name: 'my new document').first
# "select * from collection"
collection.find.each do |document|
puts document.inspect
end

Resources