Cannot find anywhere the accepted way to create a model without going through controller considering that attr_accissible is no longer supported.
Is the below approach correct?
in my old code:
ModelName.create(course_id:680, user_id:25)
(raises mass_assignment error now that I have removed attr_accessible)
new code:
model = ModelName.new.tap do |m|
m.course_id = 680
m.user_id = 25
end
model.save!
(works but looks hacky)
Apparently, the below will not work because without_protection option is removed in Rails4
ModelName.create({course_id: 680, user_id: User.first.id}, without_protection: true)
Thanks to this question I've read about strong parameters 'Use outside of Controllers' - link but even if I do the following from my console:
raw_params = {course_id: Course.last.id, user_id: User.first.id}
parameters = ActionController::Parameters.new(raw_params)
ModelName.create(parameters.permit(:course_id, :user_id))
I get error
WARN -- : WARNING: Can't mass-assign protected attributes for ModelName: course_id, user_id
I read this question more carefully and found my answer
I had to add
config.active_record.whitelist_attributes = false
to my environments (development/test/production.rb), maybe because I still have the protected_attributes gem installed.
so now I can happily use
ModelName.create(course_id:680, user_id:25)
afterall.
I realise this question/answer is somewhat of a repeat of the aforementioned question - but I did find that question a bit tricky to understand, so I won't take this question down unless asked.
Related
edit: I solved it easily by adding "https://www.googleapis.com/auth/plus.me" to my scopes, but I wanted to start a discussion on this topic and see if anyone else experienced the same issue.
I have a service running on GCP, an app engine that uses Google API. This morning, I've received this "warning" message which threw an 500 error.
It has been working fine for the past month and only threw this error today (5 hours prior to this post).
Does anyone know why Google returned an additional scope at the oauth2callback? Any additional insight is very much appreciated. Please let me know if you've seen this before or not. I couldn't find it anywhere.
Exception Type: Warning at /oauth2callback
Exception Value:
Scope has changed from
"https://www.googleapis.com/auth/userinfo.email" to
"https://www.googleapis.com/auth/userinfo.email
https://www.googleapis.com/auth/plus.me".
This line threw the error:
flow.fetch_token(
authorization_response=authorization_response,
code=request.session["code"])
The return url is https://my_website.com/oauth2callback?state=SECRET_STATE&scope=https://www.googleapis.com/auth/userinfo.email+https://www.googleapis.com/auth/plus.me#
instead of the usual https://my_website.com/oauth2callback?state=SECRET_STATE&scope=https://www.googleapis.com/auth/userinfo.email#
edit: sample code
import the required things
SCOPES = ['https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/calendar',
# 'https://www.googleapis.com/auth/plus.me' <-- without this, it throws the error stated above. adding it, fixes the problem. Google returns an additional scope (.../plus.me) which causes an error.
]
def auth(request):
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
CLIENT_SECRETS_FILE, scopes=SCOPES)
flow.redirect_uri = website_url + '/oauth2callback'
authorization_url, state = flow.authorization_url(
access_type='offline', include_granted_scopes='true',
prompt='consent')
request.session["state"] = state
return redirect(authorization_url)
def oauth2callback(request):
...
# request.session["code"] = code in url
authorization_response = website_url + '/oauth2callback' + parsed.query
flow.fetch_token(
authorization_response=authorization_response,
code=request.session["code"])
...
We discovered the same issue today. Our solution has been working without any hiccups for the last couple of months.
We solved the issue by updating our original scopes 'profile email' to https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile and by doing some minor changes to the code.
When initiating the google_auth_oauthlib.flow client, we previously passed in the scopes in a list with only one item which contained a string in which the scopes were separated by spaces.
google_scopes = 'email profile'
self.flow = Flow.from_client_secrets_file(secret_file, scopes=[google_scopes], state=state)
Now, with the updated scopes, we send in a list where each element is a separate scope.
google_scopes = 'https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile'
self.flow = Flow.from_client_secrets_file(secret_file, scopes=google_scopes.split(' '), state=state)
Hope it helps, good luck!
I am using requests_oauthlib extension and I had the same error. I fix the issue by adding OAUTHLIB_RELAX_TOKEN_SCOPE: '1' to environment variables. So my app.yaml file is similar to this:
#...
env_variables:
OAUTHLIB_RELAX_TOKEN_SCOPE: '1'
For my case I added the following line in that function that the authentication is happening in
os.environ['OAUTHLIB_RELAX_TOKEN_SCOPE'] = '1'
flow = InstalledAppFlow.from_client_config(client_config, scopes=SCOPES)
At a guess from your error it looks like you're using a depreciated scope. See:
https://developers.google.com/+/web/api/rest/oauth#deprecated-scopes
I'm also guessing that you may be using the Google+ Platform Web library and maybe the People:Get method. Perhaps try using one of the following scopes instead:
https://www.googleapis.com/auth/plus.login
or
https://www.googleapis.com/auth/plus.me
Given the timing, you might be effected by this change by Google:
"Starting July 18, 2017, Google OAuth clients that request certain sensitive OAuth scopes will be subject to review by Google."
https://developers.google.com/apps-script/guides/client-verification
I've been running into quite an annoying issue when dealing with Rails 4 action mailer previews and factory girl. Here's an example of some of my code:
class TransactionMailerPreview < ActionMailer::Preview
def purchase_receipt
account = FactoryGirl.build_stubbed(:account)
user = account.owner
transaction = FactoryGirl.build_stubbed(:transaction, account: account, user: user)
TransactionMailer.purchase_receipt(transaction)
end
end
This could really be any action mailer preview. Lets say I get something wrong (happens every time), and there's an error. I fix the error and refresh the page. Every time this happens I get a:
"ArgumentError in Rails::MailersController#preview
A copy of User has been removed from the module tree but is still active!"
Then my only way out is to restart my server.
Am I missing something here? Any clue as to what is causing this and how it could be avoided? I've restarted my server 100 times over the past week because of this.
EDIT: It may actually be happening any time I edit my code and refresh the preview?
This answers my question:
https://stackoverflow.com/a/29710188/2202674
I used approach #3: Just put a :: in front of the offending module.
Though this is not exactly an answer (but perhaps a clue), I've had this problem too.
Do your factories cause any records to actually be persisted?
I ended up using Factory.build where I could, and stubbing out everything else with private methods and OpenStructs to be sure all objects were being created fresh on every reload, and nothing was persisting to be reloaded.
I'm wondering if what FactoryGirl.build_stubbed uses to trick the system into thinking the objects are persisted are causing the system to try and reload them (after they are gone).
Here's a snippet of what is working for me:
class SiteMailerPreview < ActionMailer::Preview
def add_comment_to_page
page = FactoryGirl.build :page, id: 30, site: cool_site
user = FactoryGirl.build :user
comment = FactoryGirl.build :comment, commentable: page, user: user
SiteMailer.comment_added(comment)
end
private
# this works across reloads where `Factory.build :site` would throw the error:
# A copy of Site has been removed from the module tree but is still active!
def cool_site
site = FactoryGirl.build :site, name: 'Super cool site'
def site.users
user = OpenStruct.new(email: 'recipient#example.com')
def user.settings(sym)
OpenStruct.new(comments: true)
end
[user]
end
site
end
end
Though I am not totally satisfied with this approach, I don't get those errors anymore.
I would be interested to hear if anyone else has a better solution.
So I am trying to override Devise::RegistrationsController which they do have wiki for and tons of tutorial out there. The one thing that I can not find is the best implementation of how to override the controller whilst implementing the require admin approval feature as well.
I think I got the hang of it but before I go any further (from all the reading on the Devise's source code) I want to know, on the registrations controller there's a line that does:
resource.active_for_authentication?
However, on the Sessions controller it's just this:
def create
self.resource = warden.authenticate!(auth_options)
set_flash_message(:notice, :signed_in) if is_flashing_format?
sign_in(resource_name, resource)
yield resource if block_given?
respond_with resource, location: after_sign_in_path_for(resource)
end
What I want to know is, if it's not confirmed or the active_for_authentication returns false, where or how does the session controller check this? I tried tracing back the source code but no luck.
So anyone who's very familiar with Devise perhaps you could answer my question? Thank you.
After authenticating a user and in each request, Devise checks if your model is active by calling model.active_for_authentication?. This method is overwritten by other devise modules. For instance, :confirmable overwrites .active_for_authentication? to only return true if your model was confirmed.
You can overwrite this method yourself, but if you do, don't forget to call super:
def active_for_authentication?
super && special_condition_is_valid?
end
Whenever active_for_authentication? returns false, Devise asks the reason why your model is inactive using the inactive_message method. You can overwrite it as well:
def inactive_message
special_condition_is_valid? ? super : :special_condition_is_not_valid
end
Rails4 is getting depreciation warning when I am upgrading from rails 3.2 to rails 4.0. I have this query.
Child.find(:all, :include => :children_users, :conditions => "state = 'active' AND owner_id = #{self.id} AND children_users.user_id = #{other_user.id}")
I am getting deprecation warning as follow :-
DEPRECATION WARNING: It looks like you are eager loading table(s) (one of: splits, accounts) that are referenced in a string SQL snippet. For example:
Post.includes(:comments).where("comments.title = 'foo'")
Currently, Active Record recognizes the table in the string, and knows to JOIN the comments table to the query, rather than loading comments in a separate query. However, doing this without writing a full-blown SQL parser is inherently flawed. Since we don't want to write an SQL parser, we are removing this functionality. From now on, you must explicitly tell Active Record when you are referencing a table from a string:
Post.includes(:comments).where("comments.title = 'foo'").references(:comments)
If you don't rely on implicit join references you can disable the feature entirely by setting `config.active_record.disable_implicit_join_references = true`. (called from splits_under_100_percent at /Users/newimac/RailsApp/bank/app/models/user.rb:274)
To solve this problem, I have try like this
Child.includes(:children_users).where(state: active, owner_id: self.id, children_users.user_id = other_user.id).load
or
Child.where{(state: active, owner_id: self.id, children_users.user_id = other_user.id).includes(:children_users)}
But none of them work.
children_users.user_id = other_user.id wrong.
The correct one is: "children_users.user_id" => other_user.id
Thank You for #Zakwan. Finally, this query works.
Child.includes(:children_users).where(state: 'active', owner_id: self.id, "children_users.user_id" => other_user.id).load
I am trying to use Python 2.7.3.2 to send an email through Lotus Notes 8.5.
There are plenty of examples on how to do this in other languages, and I've done it myself in VBA, but having difficulties with Python.
self.db = self.session.getDatabase(server, dbfile)
# ...
mailDoc = self.db.CreateDocument
mailDoc.Form = "Memo"
mailDoc.sendto = recipientList
mailDoc.subject = subject
mailDoc.Body = bodytext
Error returned: AttributeError: Property 'CreateDocument.Form' can not be set.
I have attempted to skip setting the form, but it also fails on setting any of these attributes.
Would anyone have code on this, or suggestions on what to try to resolve it.
I know nothing about Python, but my guess is that the shorthand notation document.item = "foo" for setting an item value is not supported. Most likely, you need to do this:
mailDoc.AppendItemValue("Form","Memo")
(You can also use ReplaceItemValue, which is equivalent for a newly created document, and also works for updating existing documents, so many people prefer to just remember the one method name.)