Django abstractuser can't set parameters - django-forms

I am trying to set a flag when a user signs up. The flags show up on the admin site, so I know the abstract user was implemented. When I toggle them in the admin area it works as well. I just can't get the form to work for regular users. I have tried many combinations with self.instance and self.request.
def save(self, commit=True):
self.instance.user.is_member = True
### additional code that works and sets non-abstractuser parameter ####
return super(UpdateUserProfileForm, self).save(commit=commit)
def form_valid(self, form):
form.instance.user = self.request.User
# form.instance.user.is_member = True
# self.request.user.is_member = True
return super().form_valid(form)

After further research I needed to add the lines
def save(self, commit=True):
user = self.instance.user
user.is_member = True
user.save()

Related

DRF validator to modify requested data

from this serializer:
class SerializerExample(serializers.Serializer):
attr = serializers.CharField()
def validate(self, test_validate):
attr = test_validate['attribute']
if attr == 'whatever':
test_validate['attribute'] = 'check 1'
else:
test_validate['attribute'] = 'check 2'
return test_validate
Now, this is used in the endpoint:
#swagger_auto_schema(query_serializer=SerializerExample)
def create(self, request):
return request_data
So, my question is, will be modifed request.data with the validated method or not?
Ok, no, it's not going to modify the data.
And, in the other hand, If you could you shouldn't, because the official documentation says that you must returns the same data you receive.
This validation only check valid data and raise error if don't match a criteria.

How to pass extra params inside option hash in confirmation email in Rails?

I am trying to pass extra params inside the options{} hash in the confirmation email but It is just showing me subject and from headers in the mailer.
This is my code
CustomMailer.confirmation_instructions(user,token, {custom_param: "abc"})
When I show opts data inside template like this
#first_name = opts
It shows
{:subject=>"Email Confirmation", :from=>"no-reply#sample.com"}
custom mailer code is
class CustomMailer < Devise::Mailer
helper :application # gives access to all helpers defined within `application_helper`.
include Devise::Controllers::UrlHelpers # Optional. eg. `confirmation_url`
#include ApplicationHelper
default template_path: 'devise/mailer' # to make sure that you mailer uses the devise views
def confirmation_instructions(record, token, opts={})
opts[:subject] = "Email Confirmation"
opts[:from] = 'no-reply#sample.com'
if(record["admin"]==false)
#template_type = 'donor'
#first_name = opts
end
end
why it is not working?
Not a complete answer but the comments section was annoying me, try:
def confirmation_instructions(record, token, opts={})
#opts = opts
opts[:subject] = "Email Confirmation"
opts[:from] = 'no-reply#sample.com'
if(record["admin"]==false)
#template_type = 'donor'
#first_name = opts
end
end
Then in your mailer, where you were calling #first_name, call #opts and it should give you the argument you feed into the method call.

Best way to Map data?

I wanna map some data from facebook into my User class. I read now some articles about inheritance, extending, including and so on. But maybe I understand something wrong.
Is this the right approach for DataMapping in Ruby?
class User
attr_accessible :name, :address
def map_facebook
FacebookUserMapper.new(facebook_object, self)
end
end
class FacebookUserMapper
def initialize(facebook_user, user)
#facebook_user = facebook_user
#user = user
mapit
end
def self.map_it()
username
address
return #user
end
def username
#user.username = #facebook_user.name
end
def address
#user.address = #facebook_user.address
end
end
I would do like this:
def mapFacebook
FacebookUserMapper.new(facebook_object, self).call
end
class FacebookUserMapper
def initialize(facebook_user, user)
#facebook_user = facebook_user
#user = user
end
def call
username
address
self
end
# ...
end
FYI: Don't add () around methods in Ruby
The better way to map the facebook object on to your user model would be this
def self.from_omniauth(auth)
where(auth.slice(:provider, :uid)).first_or_initialize.tap do |user|
user.provider = auth.provider
user.uid = auth.uid
user.name = auth.info.name
user.oauth_token = auth.credentials.token
user.oauth_expires_at = Time.at(auth.credentials.expires_at)
user.save!
end
end
auth is the facebook object here.
tap just allows you do do something with an object inside of a block, and always have that block return the object itself.
This is a code snippet from a Railscasts episode from which you could get even more help for your facebook related app.

in UsersController#create, User.new(params[:user]) return an empty User (params looks good)

I'm kind of new to Rails 3.1. and I'm facing an issue only in my production env with my Signup form (actually, it's more about the controller).
Here is the code in User
class UsersController < ApplicationController
[...]
def create
#user = User.new(params[:user])
logger.info "value of login in param : #{params[:user][:login]}" #-> log the actual login
logger.info "value of login : #{#user.login}" #-> log empty
#user.admin = false
if #user.save
flash[:notice] = t('flash.notice.user.create.valid')
redirect_back_or_default root_path
else
flash[:notice] = t('flash.notice.user.create.invalid')
render :action => :new
end
end
end
Also, the controller logs show that the params hash is good
Parameters: {"utf8"=>"✓",
"authenticity_token"=>"QwOqmp0CT/d4mmC1yiLT4uZjP9bNDhbUXHanCQy5ZrA=",
"user"=>{"login"=>"myLogin",
"email"=>"t.r#gmail.com",
"password"=>"[FILTERED]",
"password_confirmation"=>"[FILTERED]"}}
My login form works as expected (already created users are able to sign in)
Again, this only happens in production.
EDIT: Here is my User Model
class User < ActiveRecord::Base
acts_as_authentic
#== Callbacks
before_create :set_defaults
attr_accessible :avatar ##### EDIT: TO FIX THE ISSUE, ADD THE OTHER FIELDS AS WELL
protected
def set_defaults
self.total_1 = self.total_2 = self.total_3 = 0
end
end
Just to memorialize the answer from the comments above:
Normally you can use mass assignment to set fields on a model, but when you use attr_accessible, you are then limited to only mass assigning those fields. So stuff like User.new(params[:user]) won't work; instead, you'd have to do:
#user = User.new
#user.login = params[:user][:login]
# ...etc.
#user.save
Simple add your fields to the attr_accessible list and you can go back to mass assignment.

How can I send emails in Rails 3 using the recipient's locale?

How can I send mails in a mailer using the recipient's locale. I have the preferred locale for each user in the database. Notice this is different from the current locale (I18n.locale), as long as the current user doesn't have to be the recipient. So the difficult thing is to use the mailer in a different locale without changing I18n.locale:
def new_follower(user, follower)
#follower = follower
#user = user
mail :to=>#user.email
end
Using I18n.locale = #user.profile.locale before mail :to=>... would solve the mailer issue, but would change the behaviour in the rest of the thread.
I believe the best way to do this is with the great method I18n.with_locale, it allows you to temporarily change the I18n.locale inside a block, you can use it like this:
def new_follower(user, follower)
#follower = follower
#user = user
I18n.with_locale(#user.profile.locale) do
mail to: #user.email
end
end
And it'll change the locale just to send the email, immediately changing back after the block ends.
Source: http://www.rubydoc.info/docs/rails/2.3.8/I18n.with_locale
This answer was a dirty hack that ignored I18n's with_locale method, which is in another answer. The original answer (which works but you shouldn't use it) is below.
Quick and dirty:
class SystemMailer < ActionMailer::Base
def new_follower(user, follower)
#follower = follower
#user = user
using_locale(#user.profile.locale){mail(:to=>#user.email)}
end
protected
def using_locale(locale, &block)
original_locale = I18n.locale
I18n.locale = locale
return_value = yield
I18n.locale = original_locale
return_value
end
end
in the most resent version of rails at this time it's sufficient to use
"I18n.locale = account.locale"
in the controller and make multiple views with the following naming strategy
welcome.html.erb,
welcome.it.html.erb and e.g.
welcome.fr.html.erb
None of the above is really working since the version 3 to translate both subject and content and be sure that the locale is reseted back to the original one... so I did the following (all mailer inherit from that class:
class ResourceMailer < ActionMailer::Base
def mail(headers={}, &block)
I18n.locale = mail_locale
super
ensure
reset_locale
end
def i18n_subject(options = {})
I18n.locale = mail_locale
mailer_scope = self.class.mailer_name.gsub('/', '.')
I18n.t(:subject, options.merge(:scope => [mailer_scope, action_name], :default => action_name.humanize))
ensure
reset_locale
end
def set_locale(locale)
#mail_locale = locale
end
protected
def mail_locale
#mail_locale || I18n.locale
end
def reset_locale
I18n.locale = I18n.default_locale
end
end
You just need to set the locale before you call the mail() method:
set_locale #user.locale
You can use the i18n_subject method which scope the current path so everything is structured:
mail(:subject => i18n_subject(:name => #user.name)
This simple plugin was developed for rails 2 but seems to work in rails 3 too.
http://github.com/Bertg/i18n_action_mailer
With it you can do the following:
def new_follower(user, follower)
#follower = follower
#user = user
set_locale user.locale
mail :to => #user.email, :subject => t(:new_follower_subject)
end
The subject and mail templates are then translated using the user's locale.
Here's an updated version that also supports the '.key' short-hand notation, so you don't have to spell out each key in its entirety.
http://github.com/larspind/i18n_action_mailer
The problem with the mentioned plugins are that they don't work in all situations, for example doing User.human_name or User.human_attribute_name(...) will not translate correctly. The following is the easiest and guaranteed method to work:
stick this somewhere (in initializers or a plugin):
module I18nActionMailer
def self.included(base)
base.class_eval do
include InstanceMethods
alias_method_chain :create!, :locale
end
end
module InstanceMethods
def create_with_locale!(method_name, *parameters)
original_locale = I18n.locale
begin
create_without_locale!(method_name, *parameters)
ensure
I18n.locale = original_locale
end
end
end
end
ActionMailer::Base.send(:include, I18nActionMailer)
and then in your mailer class start your method by setting the desired locale, for example:
def welcome(user)
I18n.locale = user.locale
# etc.
end

Resources