Location for user_parameter_sanitizer.rb - ruby-on-rails-4

Recommendation from GitHub devise gem:
If you have multiple Devise models, you may want to set up a
different parameter sanitizer per model. In this case, we recommend
inheriting from Devise::ParameterSanitizer and adding your own
logic:
class User::ParameterSanitizer < Devise::ParameterSanitizer
def initialize(*)
super
permit(:sign_up, keys: [:username, :email])
end
end
And then configure your controllers to use it:
class ApplicationController < ActionController::Base
protected
def devise_parameter_sanitizer
if resource_class == User
User::ParameterSanitizer.new(User, :user, params)
else
super # Use the default one
end
end
end"
Where should I create the file user_parameter_sanitizer.rb to host the code?
The info given by the devise GitHub page is excellent, but I am new to Rails and coding in general.

Related

Overriding a child association's setter from the parent model

I have a parent User model, and each user has_one Contact which hold's the user's contact info.
One of the contact fields is the email. For various legacy reasons and reasons outside the context of this question, I'd love to be able to call #email directly as if it were a property of User
In other words I'd like to do this -
user.email
user.email = "foo#example.com"
Instead of this -
user.contact.email
user.contact.email = "foo#example.com"
I laid out my models as follows, overriding the child's getter/setter from the parent User -
class User < ActiveRecord::Base
has_one :contact
def email
contact.email
end
def email=(value)
contact.email = value
end
end
class Contact < ActiveRecord::Base
belongs_to :user
end
You may have already noticed the problem with the setter - when the User is saved, it doesn't save the child model.
What's the most robust to work around this?
Thanks!
Ok, found the solution for anyone curious - auto-saving
ActiveRecord::AutosaveAssociation is a module that helps with exactly this - saving child associations properly when the parent is saved.
Just need to include an autosave: true. Example -
has_one :contact, autosave: true
It also takes care of destroying records marked for deletion, and a few other fancy things.
I also did a quick check, and it smartly doesn't hit the DB unless it really needs to. That is, if you update the parent only it doesn't bother saving the child association with an other SQL UPDATE statement.
Check out the documentation here.

Is there a better way of overriding devise controller in rails

I have to populate a field in my db when a new user signs-up.But this field is not to be filled by the user, instead will be populated by the application in the db. Here is what i tried:
Added the extra field(investorId) in the migration file.
Overridden the devise controller:
def create
super
if #user.save
#user.investorId = #user.id + X---> some number
#user.save
end
end
Though it is working fine, but I want to know if there are better ways of doing it since I am doing it for the first time.
Thanks,
Sachin
If you need to generate a value before you create a record, you can use the before_create or after_create callbacks on the model.
User < ActiveRecord::Base
after_create :generate_investor_id
private
def generate_investor_id
reload
investor_id = "#{self.id}something"
update_attribute(:investor_id, investor_id)
end
end
Don't override your devise controller, there is no benefit of doing this. Simply put the below logic in your after_create callback -
User < ActiveRecord::Base
after_create :create_investor_id
private
def create_investor_id
self.update_column(:investor_id, id+some_number)
end
end

Rails user experience vs file structure with carrierwave and nested forms - Need input on design decisions

I have 2 models, product and a photos model as follows:
product.rb
class Product < ActiveRecord::Base
has_many :photos, dependent: :destroy
accepts_nested_attributes_for :photos, allow_destroy: true
end
photo.rb
class Photo < ActiveRecord::Base
belongs_to :product
validates :album, presence: true
mount_uploader :image, PhotoUploader
end
I'm using carrierwave & s3 for file uploads.
I can nest the forms so that users can upload photos at the same time that they create the product. In this scenario, the photo models are saved before the product model is saved, which leads to a photo file path of something like:
uploads/photos/images/photo_id
But the file structure would make more sense if it was something like:
uploads/product/id/photos/
However, product.id is nil at the time of photo creation.
With that in mind, a few questions:
Does the file structure really matter that much or am I over thinking it?
Should I do something instead where the product is saved first with basic info and then the files are attached on a separate form?
Is there something I'm overlooking like a way to trigger carrierwave to move the files after the product model is saved?
From a UI standpoint is it bad practice to have users go thru a multi-step process (in this case for creating a product)?
My solution to have a path such as uploads/products/id/photos/ is to configure the PhotoUploader as follows:
def store_dir
"uploads/products/#{model.product_id}/images"
end
Just be careful that there are no validations that would cause product_id to be non-existant at the time the store_dir method is called.

How to test the model with Minitest & no database?

I am using rails 4.2.1 & ruby 2.2.1 in my appliation. So minitest is automatically added which is of version 5.1. There is no database in my application.
With database I am able to test the model. How do I test the model without database?
I have created a user model:
class User
include ActiveModel::Model
end
users.yml:
one:
firstName: Avi
email: a#a.a
user_test.rb:
require 'test_helper'
class UserTest < ActiveSupport::TestCase
test "the truth" do
user = users(:one)
assert true
end
end
Here I am getting the error: Undefined methods users. I am getting proper data if daabase exists.
I even tried adding include ActiveModel::Lint::Tests still getting the same error.
Can anyone help me on this?
Thanks
The class ActiveSupport::TestCase expects that a database connection is active. You probably want to switch that to Minitest::Test, but that means that you can't use the users fixture method to retrieve a record from the database.
require 'test_helper'
class UserTest < Minitest::Test
def test_sanity
user = User.new
user.first_name = "Avi"
user.email = "a#a.a"
assert user
end
end

Call Back for belongs_to association rails

Like after_add callback for has_and_belongs_to_many association is there any call back or work around to get after_add functionality for belongs_to association.
One work around is to use after/before save call backs and dirty object functionality.
belongs_to :video
after_save :after_save_task
def after_save_task
do_stuff if video_id_changed?
end
def do_stuff
### do stuff
end
But I cannot save(true) in do_stuff since its going into an infinite loop.
Looks like the feature for adding callbacks for has_on and belongs_to is not yet added. see this thread https://github.com/rails/rails/issues/586
One dirty solution for your specific problem would be to add some dirty attribute to suggest if update has already been made.
like this
belongs_to :video
after_save :after_save_task
attr_accessor :stuff_done
def after_save_task
do_stuff if video_id_changed? && !stuff_done
end
def do_stuff
stuff_done = true
### do stuff
## Saving record here would be fine.
end
Again this is truly a hack, there might exist some better solution for this.
How about overriding the setter method?
Rails guides has an exam0le of this here
an excerpt of which states
Overriding generated methods
Association methods are generated in a module that is included into
the model class, which allows you to easily override with your own
methods and call the original generated method with super. For
example:
class Car < ActiveRecord::Base belongs_to :owner belongs_to
:old_owner
def owner=(new_owner)
self.old_owner = self.owner
super
end
end
If your model class is Project, the module is named
Project::GeneratedAssociationMethods. The GeneratedAssociationMethods
module is included in the model class immediately after the
(anonymous) generated attributes methods module, meaning an
association will override the methods for an attribute with the same
name.
I appreciate this is an old question but I stumbled on it looking for a similar solution