How to handle ActiveSupport::MessageVerifier::InvalidSignature errors for ActiveStorage direct uploads - rails-activestorage

I have a form where a user selects a file to upload. The file is uploaded once the file is selected using ActiveStorage direct uploads. There is a submit button that is not clickable until the upload is complete.
The button is disabled when the form loads. However, if for some reason the user was able to click the button without first selecting a file I get the following error in my controller:
ActiveSupport::MessageVerifier::InvalidSignature - ActiveSupport::MessageVerifier::InvalidSignature:
I want to make sure my application is solid so I want to know how to deal with this error.
Here is my controller method:
def create
authorize [:proofreaders, :proofread_document]
#proofread_document = ProofreadDocument.build(proofread_document_params.merge(uploader: current_user, proofreading_job: #proofreading_job))
if #proofread_document.save
flash[:notice] = I18n.t('success.upload', resource: #proofread_document.file.filename)
render :create, layout: false
else
render :new, layout: false
end
end
My attempt to deal with this issue is to create my own 'build' method and use it instead of the standard 'new' because 'new' raises the error in my controller and I want to deal with this in the model.
The 'build' method in my model:
def self.build(params)
pd = self.new params.except(:file)
pd.file = params[:file]
pd
rescue ActiveSupport::MessageVerifier::InvalidSignature => e
pd
end
I have to separately assign the file attribute value to the model so the other attributes will get assigned before the error is raised.
This works as it returns the instance of the model that was setup before the error occurred and the validation of the file checks for an empty file value. However, is this really correct and is there a better way that more experienced and skilled developers are using?

The way that I know how to solve this off the top of my head is to modify the params to reject blank values. for example
params[:user].delete(:avatar) if params[:user][:avatar].blank?
This works but it will make your controller action harder to look at I want to resolve this on the model side so Ill do that and fill you in how that turns out.

For some reason this solved my problem.
def user_params
params.permit(
:id, :name, :email, :username, :country, :avatar, :id_number, :license_number
).select {|x,v| v.present?}
end
Looks like the empty value is causing the issue
"id_number"=>"234545", "license_number"=>"234545", "avatar"=>""
My model
class User < ApplicationRecord
has_one_attached :avatar

Related

Displaying a form and saving the submited data

I have a simple app that saves and displays records off of a database,
#user_endpoints.get("/user/<id>")
def get_user(request, id):
dct = User.by_id(id)
if not dct:
return response.json({"Error": "Not Found"}, status=404)
return response.json(dct.to_dict(), status=200)
When it comes to displaying a user list something like the code below was sufficient,
#user_endpoints.get("/users")
def list_users(request):
dct = User.all()
template = template_env.get_template('user_list.html')
content = template.render(title='User List', users=dct)
return response.html(content)
The above uses Jinja2 but that is not important to me (this is not a real app). I am not clear on how to display a form for creating a new user and saving the submitted data, can someone provide a simple example for that?
There is no "one way" with Sanic to do that. Sanic does not know about forms. It completely depends on what you do in the frontend, how you encode the data. Are you sending JSON or is it "form-data" encoded? Maybe something completely different?
You would certainly use "POST" instead of "GET" like you did above. You can inspect request and find your data that's been sent from the frontend and then act on it. (Although nowadays you'd start with designing and implementing a proper (REST) API - usually based on JSON - and then use that. The word "form" does not appear here. It's just data.)
You could use Sanic-WTF
There is an example with Sanic-WTF + Jinja2 - https://bitbucket.org/voron-raven/synergy/src/1b8172a0bc61c5239c5ad2a2b9f064ed50ff81dd/views.py#lines-88

How to navigate Edge extension local storage callback requirements

I'm trying to access the local storage data in Edge set by my options page, using my popup script. Is there a current, working example of this available?
I was using localStorage, but it would only update the popup if I reloaded the extension after saving changes in my options page. I want to make it easier on the user by allowing the popup to access it immediately after saving, without reloading. I found the browser.storage.local.get(), but documentation conflicts everywhere I look, and I can't find viable working examples.
I have used, per Edge documentation:
browser.storage.local.get("sample");
But it throws an error requiring a callback function. So then I used:
let sample = browser.storage.local.get("example");
sample.then(ifGood, ifBad);
I get an error regarding property "then".
Then I simply tried adding a callback to the action itself:
sample = browser.storage.local.get("example", callbackFunction);
function callbackFunction(data){
alert(data);
}
The end alert should display a string, but it just displays an empty Object. How do I access the data returned in the callback? I tried callbackFunction(this) as an argument in the get, but it throws an error about the syntax of the get.
I found a work-around using browser.runtime.reload() in the Options page when saving the changes. It still reloads the extension, but it does it without requiring the user to do it manually.
You should use this syntax:
browser.storage.local.get(propertyName | null, callbackFn)
where
callbackFn = function fn(resultObject) {...}
When you pass null you will get whole storage object.
Look for example 1 or example 2 in my Edge extension.

Identifying an element in Visual Studio UI coded test

I'm trying to set up a coded UI test to allow me to check for an error message on a login. The test runs, but I'm struggling to get the assert to work.
The response that comes back is nested as follows:-
<div class='ui-errors'>
<ul>
<li>Your password is invalid</li>
</ul>
</div>
What do I need to set up to check the first li in the div of that class in an assert?
Coded UI can capture DIV. In the following code I've created a custom DIV object from your provided example. AdrianHHH's answer will definitely get you information you need to insert in to my example.
var error = new HtmlDiv(new Parent(RootParentWindow));
error.SearchProperties.Add("Class", "ui-errors");
var errors = error.FindMatchingControls();
foreach (var item in errors)
{
Assert.IsTrue(item.GetProperty("InnerText").ToString().Contains("Your password is invalid"));
}
Coded UI does not really look at DIVs or ULs etc. Coded UI looks at what is drawn on the display. I suggest you use the Coded UI cross-hair tool to examine the error message then add an assertion to check for the message. You might also examine the same area of the screen for a test which passes to see how they differ.
If you are hand coding your test rather than letting Coded UI generate the code for you, I recommend creating a sandbox project and recording the assertion into that. Then copy the useful ideas from the generated code into your own test code.
If you can get a sample of the page where the assertion is needed I could create it for you, otherwise do what AdrianHHH said.
In case you don't know when you use the assertion tool, all the options you get are different ways to assert that particular control, eg you could assert if it exists or if the inner text is equal etc.
yonitdm answer will solve your problem, but as per your words, "first li in the div of that class" try below.
// Find Error Div
var errorDiv = new HtmlDiv(new Parent(RootParentWindow));
errorDiv.SearchProperties.Add("Class", "ui-errors");
errorDiv.Find();
// Get UL - First item in div
var errorUL = errorDiv.GetChildren().First(); // or GetChildren()[0]
// Get all LIs and take first item
var firstLI = errorDiv.GetChildren().First(); // or GetChildren()[0]
Assert.IsTrue(firstLI.GetProperty("InnerText").ToString().Contains("Your password is invalid"));

Rails ActiveAdmin - after creating a post I wish to render an action

I'd like to know how can I render an action after creating a post on ActiveAdmin. My idea is after I create a post I'd like to get it's tags. I searched all over internet and there's not sufficient documentation.
I just saw that I can override the create action, but now I get a missing template error, can someone post some example code for overriding create in this situation?
In your Post model:
after_create :get_tags
def get_tags
tags = Post.find(:last)
tags = tags.tag
# return values
self.get_tags
end
In your AA definition:
controller do
def create
# Do your stuff
# You can try one of this:
# render :action => :show
# render "path/to/template" , :layout => "active_admin"
end
end
Not big fan of rails model callbacks I would recomend using active admin controller callbacks in this case.
controller do
after_create :get_tags
def get_tags(post)
post.get_tags
end
end
I've had a similar issue a few days ago, the way I solved it was like this.
in your model
after_create :method_name
def method_name
whatever you need to do
end
Be careful that if you are going to update attributes in the DB to use:
model.update_attributes(:attribute_name => new_value)
and not
model.save!
I spent a few days until I found out that save doesn't work.

drupal_add_js() only adds the JS when no error message (D6)

In my custom form (in a custom module) drupal_add_js() only adds the JS when there is no error message.
My code goes like this:
function ntcf_redo_order_form( &$form_state = array() ) {
global $base_path, $user;
$my_dir = drupal_get_path('module', 'ntcf_redo');
drupal_add_js("$my_dir/order.js", 'module', 'header', FALSE, TRUE, FALSE);
$form = array();
...
return $form;
}
If the validation function used _form_set_error()_ to display an error message and highlight the offending field, the message is displayed and the field highlighted, but the _drupal_add_js()_ call does nothing. Without a pending error message to display, all is well.
EDIT: this problem does not occur with drupal_set_message(), only with form_set_error().
I tried adding the 3 later parameters to the *drupal_add_js()* call to tell it to not optimize it (don't combine it with other JS files). There is no mention of the file order.js in the HTML, and it makes no difference whether I use the last 4 parameters ('header', FALSE, TRUE, FALSE) or not.
In Admin/Performance, I turned off Optimize Javascript Files, and pretty much all caching, which also made no difference.
Extra Details:
I'm not sure if this makes a difference, but it wouldn't surprise me, so here goes:
What I'm doing here is a multi-part "wizard" form that allows the user to proceed forward and go back. Also, many of the pages use AJAX, so I need to do all the "required" field validation in the _submit function instead of letting Drupal do it automatically (since that makes a mess of AJAX). So, if there's a "required" field that's missing, the _submit() function sets an error message, and the form generation function generates the same form again (with the additional decoration resulting from the error message).
Also: this is off-topic, but it might help someone using Google: when doing a multi-page form that allows going backward, you MUST assign a weight to every item on the form, or else the fields tend to "wander" when you go backwards.
Any ideas?
I had the same problem, this is a workaround I found (for Drupal 7, may work in 6) :
1. in your form setup (or hook_form_alter), do this :
$form['#post_render'][]='yourfunction';
2. define :
function yourfunction($content,$element){
$my_dir = drupal_get_path('module', 'ntcf_redo');
drupal_add_js("$my_dir/order.js", 'module', 'header', FALSE, TRUE, FALSE);
return $content;
}
I think this works (while your approach does not), because hook_form_alter (and/or hook_form)
do NOT get called again for a prepared/cached form, so the initial form load WILL load the javascript, but subsequent posts will NOT.
HTH
Mikes answer ($form['#post_render'][]='yourfunction';), will work, though its not the optimal way and will cause issues with drupal_add_js.
The best way to do this is by adding your javascript via the form api '#attached'.
Instead of using drupal_add_js or a new callback on the '#post_render':
$form['#attached']['js'] = array(
drupal_get_path('module', 'module_name') .'/file/path/filename.js',
);
You may pass in a 'css' array as well. Being an array, you can pass in as may files as you want.
*This is for Drupal 7. Other versions may be different.

Resources