Rails 5.1.4 active storage MissingModelIdError - amazon-s3

Rails newbie here. I am trying to upload a file to S3 via active storage through a background job. Set up everything as mentioned in this article (https://keithpblog.org/post/active-storage-on-amazon-s3/.)
When I run the background job I get this error. Searched google but I couldn't find anything relevant.
Can someone please help me out?
The below is how my model looks
class ReportOutput < ApplicationRecord
has_one_attached :output_file
end
This is how I am calling it. (not sure if this is correct way)
ReportOutput.new.output_file.attach(io: File.open('./test.xlsx'), filename: 'test.xlsx')
This is the error I get.
Job exception: #<URI::GID::MissingModelIdError: Unable to create a Global ID for ReportOutput without a model id.>

Related

Does chef 'notifies :action, 'resource', :before' work at all as it should?

I've recently tried to perform a simple task: Install a package if it does not exist by pulling distribution out of web location (in-house repo) and deleting it once it is not longer needed.
Learning about :before notification I came up with following elegant code (in this example variable "pkg" keeps name of distribution image, "pkg_src_location" is URL of my web repository, "name_of_package" is named installed package):
local_image = "#{Chef::Config['file_cache_path']}/#{pkg}"
remote_file 'package_image' do
path local_image
source "#{pkg_src_location}/#{pkg}"
action :nothing
end
package name_of_package do
source local_image
notifies :create, 'remote_file[package_image]', :before
notifies :delete, 'remote_file[package_image]', :delayed
end
I was quite surprised that it does not work... Actually 'package' resource is being converged without 'remote_file' being created - and it fails due to source local_image not being in place...
I did a simple test:
log 'before' do
action :nothing
end
log 'after' do
action :nothing
end
log 'at-the-end' do
action :nothing
end
log 'main' do
notifies :write, 'log[before]', :before
notifies :write, 'log[at-the-end]', :delayed
notifies :write, 'log[after]', :immediately
end
What I learned is that 'main' is actually converged twice! Once when first encountered and once again, after 'before' resource is converged...
Recipe: notify_test::default
* log[before] action nothing (skipped due to action :nothing)
* log[after] action nothing (skipped due to action :nothing)
* log[at-the-end] action nothing (skipped due to action :nothing)
* log[main] action write
* log[before] action write
* log[main] action write
* log[after] action write
* log[at-the-end] action write
Is it a bug or feature? If this is 'feature', it is a really bad one and Chef shouldn't have it at all. It is simply useless the way it works and only wastes people's time...
Can anyone having more in-depth Chef understanding comment on it? Is there any way to make ':before' work? Maybe I'm just doing something wrong here?
To be a bit more specific, the before timing uses the "why run" system to make a guess about if the resource needs to be updated. In this case, the package resource is invalid to begin with so whyrun can't tell that an update is needed.
After a little rethink about it I get what's going wrong here:
The before notification is fired if the actual resource will have to be updated, in chef inner this mean getting the actual resource state to compare to the desired resource state ('\load_current_resource\ in providers).
Here you're willing to install a package, chef will ask the system about this package and it's version, and then will compare this result with the source you provided.
And here comes the problem, you can't compare with the source package as it is not installed.
For your case, the best bet is to leave the file on the system and get rid of notifications.
The before notification could be of interest if you want to launch a database backup before upgrading the DB system for example or as mentioned in the RFC for :before to stop a service before upgrading its package.
But it should not be used to trigger another resource providing one of the "calling" resource properties.

How to use 'Whenever' gem?

I'm currently trying to use the whenever gem to schedule my tasks but I do not know how it works. I've tried following the steps at https://github.com/javan/whenever but I got stuck at schedule.rb file. What am I supposed to write inside here? I want my app to call a method every minute using this gem. How am I supposed to do it? Can anyone give me a clue on how to do so?
UPDATE
I did the following to my application whereby it's supposed to send out an email every minute. I tried running the method without the scheduling and it works but it doesn't work if i schedule it, like the codes below. Is there something wrong with my code?
1) schedule.rb
every 1.minute do
runner "Newsletter.schedule_email"
end
2) newsletter.rb
def schedule_email
...*codes*...
end
Well, the basic form would be:
every 1.minute do
runner "Class.method_name"
end
If your stuff isn't running, this question might have some useful info:
Whenever cron job is not working in rails 3
There's also a railscast about cron jobs in general and Whenever in particular:
http://railscasts.com/episodes/164-cron-in-ruby

logging info with rails

Moving over from django / python, I am having a little trouble getting the rails logger to log all the information I want. I am wondering how/if the following can be achieved:
Having in the log format(ter) include the specific file, function name and line where the logging statement itself was found. Essentially the equivalent of LOG_MSG_FORMAT = '%(asctime)s %(levelname)s %(filename)s:%(funcName)s(%(lineno)d) : %(message)s' in python logger?
Being able to log all requests, via something similar to a django request logging middleware. Particularly, being able to log the username (if logged in) of every request.
Am I missing something obvious? or does this require (lots of) custom code?
I just found this railtie gem that might help although I imagine it will take some "custom code" to append username to logs. See the Readme section on logging specific controllers and models.
logging-rails railtie
I don't know about getting the file, function, and line number, but it's pretty easy to log from application_controller:
class ApplicationController < ActionController::Base
before_filter :log_user
def log_user
if current_user
Rails.logger.info "Processing Request for #{current_user.name}"
end
end
end
Just to add a quick note in case this is useful for someone:
The lograge gem makes rails logs much similar to django's, plus allows very neat customization, adding parameters such as remote ip address, current_user etc.
It also reduces verbosity of rendered layouts, which I anyway found unnecessary for production. It also plays nicely with logging-rails railtie mentioned by #lukewendling.
Sadly, I still couldn't find anything that shows the file/function/line number like you can easily do with django, but I guess that's just too much to ask.

How to read params from Transloadit upon successful upload to s3

i am using Transloadit to process and store my pic to amazon s3. The upload works fine, however upon successful redirect back to my app i get an error when trying to access one of the vales from the hash of params sent by transloadit.
<%= params[:transloadit][:ok] %>
The error returned is
can't convert Symbol into Integer
and the hash of params looks like this:
{"transloadit"=>"{\"ok\":\"ASSEMBLY_COMPLETED\",
\"message\":\"The assembly was successfully completed.\",
\"assembly_id\":\".........\",
\"assembly_url\":\"http://api2.donnie.transloadit.com/assemblies/....\",
\"bytes_received\":351697,
\"bytes_expected\":351697,.........}
I am using the gem transloadit/rails-sdk for easy integration into my app. On their github page they say and i quote:
"If you want to use the automatic transload parameter decoding, you have to include the Transloadit::Rails::ParamsDecoder module into your controller
class YourController
include Transloadit::Rails::ParamsDecoder
end
that way the param[:transloadit] is automatically decoded for you, if it exists"
I am not sure what they mean by this (even if i include this into my controller i get an error with a different set of params). What is the purpose of this line?
All i need is to access the params[:transloadit][:ok] parameter. How can i get hold of this parameter? thanks
I had a similar problem. If you use key names instead of symbols, it might help. I'm not sure why, but that's what I had to do. Try params["transloadit"]["ok"] or some variation of that.

Mongoid, confused with embedded document with timestamps and versioning?

I have been using Mongoid for about 3 months now, and I have managed to get done pretty much anything I need thanks to the great document and resources out there.
But going back to improve some stuff I have made a few backs, I am definitely struggling a lot on embedded documents.
In a nutshell what I am trying to do, is to maintain versioning and timestamps on embedded documents, but that I cannot manage to do.
Here is the relevant part of my model:
class Content
include Mongoid::Document
include Mongoid::Timestamps
include Mongoid::Paranoia
embeds_many :localized_contents
accepts_nested_attributes_for :localized_contents
end
class LocalizedContent
include Mongoid::Document
include Mongoid::Timestamps
include Mongoid::Paranoia
include Mongoid::Versioning
embedded_in :content, :inverse_of => :localized_contents
end
Nothing really complicated here, everything works fine regarding the behavior of the Content model, however the LocalizedContent model is not behaving the way I am expecting to, so my expectations either needs to get straighten up, or I need help fixing what I am doing wrong.
To create a new embedded document I do the following:
my_content = Content.find(params[:id])
my_content.localized_contents.build(params[:localized_content])
if parent.save
#redirect, etc.
end
This works in the sense that it successfully creates a new embedded document in the correct Content, however the timestamps fields I left a nil
Now, if I try to update that localized_content:
my_content = Content.find(params[:content_id])
localized_content = my_content.localized_contents.find(params[:id])
Now, if I do: localized_content.update_attributes(params[:localized_content]) I get the following error:
=> Mongoid::Errors::InvalidCollection: Access to the collection for LocalizedContent is not allowed since it is an embedded document, please access a collection from the root document.
Fair enough, then I update atomically the fields on the localized content and save the parent:
localized_content.fieldA = "value"
localized_content.fieldB = "value"
localized_content.fieldC = "value"
my_content.save
This works in updating the localized content properly but:
- timesteamps (udpated_at and created_at) are still nil
- versions does not receive the a copy of the current localized_content and version does not get incremented !
So as I read in many occasion in this groups and on some forums on the web, the call backs are not triggered on the embedded document for performance reason, since I am calling save on the parent. Again, faire enough, but as suggested in those places, I should call save on the embedded docs instead... but how !?!?! because every time I do I get the dreaded:
=> Mongoid::Errors::InvalidCollection: Access to the collection for LocalizedContent is not allowed since it is an embedded document, please access a collection from the root document.
Even more so, I tried to manually call the call back for versioning on my embedded: localized_content.revise, and again same error:
=> Mongoid::Errors::InvalidCollection: Access to the collection for LocalizedContent is not allowed since it is an embedded document, please access a collection from the root document.
I am going nuts here ! Please help. What I am doing wrong ? How should an embedded document be create and updated so I can call (even manually I don't care) the proper callbacks to update the time stamps and versioning ?
Thanks,
Alex
ps: I am using rails 3.0.3 and mongoid 2.0.1
Just in case this answer is still useful to anyone, Mongoid has added a tag which makes callbacks run on embedded child objects when the parent object is saved.
Your parent object should now look like this:
class Content
include Mongoid::Document
include Mongoid::Timestamps
include Mongoid::Paranoia
embeds_many :localized_contents, cascade_callbacks: true
accepts_nested_attributes_for :localized_contents
end
That's it! Now, saving the parent object will run callbacks on the child objects (and Mongoid::Timestamps is smart enough to only run on the objects which were actually changed). This information is in the mongoid documentation, at the very bottom of the embedded documents page.
Try using create instead of build. EmbeddedDoc.build and EmbeddedDoc.new won't fire any save callbacks (because nothing's being saved yet), and saving the parent doc won't call the embedded children's callbacks (performance decision). EmbeddedDoc.create should fire the embedded docs callbacks though.
my_content = Content.find(params[:id])
puts my_content.localized_contents.create(params[:localized_content])