Mixed attr_accessible and strong_parameters, how to skip attr_accessible? - ruby-on-rails

First of all, I am fully aware of the bad practice with mixing the two.
I have a model that has attr_accessible set up. I'd like to start transitioning our application to strong_parameters. The problem is that I need to do this piecemeal as we refactor individual parts of the application. Is there a ActiveRecord method I can use to update the attributes that bypasses attr_accessible for right now? Or can I define a attr_accessible=false type of thing that bypasses it?
Code example:
Model:
class User < ActiveRecord::Base
attr_accessible :first_name, :last_name, :email, :password
end
Controller:
class UsersController < ApplicationController
before_action :set_user
def update
#user.assign_attributes(user_params)
#user.save!
end
private
def set_user
#user = User.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
params.require(:user).permit(
:first_name, :last_name, :email, :other_attribute_not_in_accessible
)
end
end

Found it!
In the controller, do this:
#user.update_attributes(user_params,:without_protection=>true)
And then it'll work.

Related

Rails - How to add additional column value into Devise registration table?

User Model
class User < ApplicationRecord
belongs_to :tenant, dependent: :destroy
end
Tenant Model
class Tenant < ApplicationRecord
has_many :users
end
Controller
Workaround 1 (not working)
def create
super
#tenant = Tenant.new
#user = #tenant.build_user(params)
#tenant.save
end
Workaround 2 (not working)
def create
#tenant = Tenant.new
#user = User.build(params)
#tenant.save
super
end
Is there any possibilities to pass a parameter to devise super class?
Since Devise super method has its own functionality on user registration/password hashing/, I can not completely override the function.
I know the way I am saving is wrong, please suggest me the better approach.
Actual source code:
(with Controller, Model, Migrations and Routes files are added.)
https://repl.it/#aravin/HarmlessRepentantHarddrive
You can override the sign_up_params in your controller:
class RegistrationsController < Devise::RegistrationsController
private
def sign_up_params
params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation...).merge({tenant_id: Tenant.create!.id})
end
end
I wanted to provide a little more verbose answer than was provided by AbM.
You can generate the registrations_controller.rb file with the following command:
rails g devise:controllers users -c=registrations
Once you do this, you will want to modify it such that you have something like:
class RegistrationsController < Devise::RegistrationsController
private
def sign_up_params
params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation)
end
def account_update_params
params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation, :current_password)
end
end
Then in your routes.rb file you will want to change the devise_for line to tell devise that you want to override your registrations controller like:
devise_for :users, controllers: { registrations: 'users/registrations' }
Of course, you will want to replace the :user/:users references to the name of your devise authentication model if you are using something other than the standard User throughout my example.
Here is a reference to this in the official docs on GitHub.

Setting a basic entity while creating a new user in Devise

Im using Devise to create my users in an App with Ruby on Rails.
I have a User model that has a Plan (hobby,premium, etc...)
When creating a new user, I want to add the basic plan to this new user (for business rules needs, I cant leave it blank).
The question is, how can I add this plan when creating this new user?
Here is my controller:
class RegistrationsController < Devise::RegistrationsController
clear_respond_to
respond_to :json
def save_user_type
session[:user_type] = params[:user_type]
end
private
def sign_up_params
params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation, :type, :provider )
end
end
In which method should I add something like this?
#user.plan = Plan.first
#user.save
class User < ActiveRecord::Base
has_one :plan
after_create :build_default_plan
private
def build_default_plan
plan.create(#paln_params)
#.. so on
end
end
Added this line to the user model
after_create do |user|
user.plan = Plan.first
user.save
end

How to save attributes using Form Objects in Rails

I have a user model which consists of 8-10 attributes.
I tried to use form object concept to extract out the validations stuffs into another UserForm Class.
FYI I am using Rails 4 :)
My controller :
class UsersController < ApplicationController
def create
#user = UserForm.new(user_params)
#user.save
end
def user_params
# Granted permission for all 10 attributes.
params.require(:user).permit(:first_name, :last_name, :email....)
end
end
My custom class looks like this:
class UserForm < ActiveModel::Validator
# like this i have 10 attributes
attr_accessor :first_name, :last_name, :email, ....
#validation for all 10 attributes
def save
if valid?
persist!
true
else
false
end
end
private
def persist!
#I think this is a bad idea, putting all 10 attributes.
#User.create(first_name: first_name, email: email, .... )
# what better solution we can have here ?
end
end
Now everything seems quite good so far. Just I am confused how to get all attributes saved directly with User.create (in persist! method) rather than manually assigning each and every value ?
UserFrom.create(user_params)
Also, why not just User.create(user_params) ?
have you looked into "Virtus" gem. it makes dealing with Form object really easy.
https://github.com/solnic/virtus
class UserForm < ActiveModel::Validator
include Virtus.model
attr_accessor :user
attribute :first_name, String
attribute :last_name, String
attribute :email, String
and so on..
def save
if valid?
persist!
true
else
false
end
end
private
def persist!
#user = User.create(self.attributes)
end
end

Rails 4 strong params get permit from nested model

There are several questions for strong params, but I couldn't find any answer for achieving my goal. Please excuse any duplicates (and maybe point me in the right direction).
I'm using strong params in a model that has several 'has_one' associations and nested attributes with 'accepts_attributes_for'.
In my routes I have: (updated for better understanding)
resources :organisations do
resources :contact_details
end
So, i.e. for one associated model I have to use
def organisation_params
params.require(:organisation).permit(:org_reference, :supplier_reference, :org_type, :name, :org_members, :business, :contact_person, contact_detail_attributes: [:id, :contactable_id, :contactable_type, :phone, :fax, :mail, :state, :province, :zip_code, :street, :po_box, :salutation, :title, :last_name, :first_name, :description])
end
This works, but I have to retype all my permitted params for each associated model. When I modify my permitted attributes for contact_details , I have to change it in several locations (every model that has the polymorphic association).
Is there a way to get the parameter whitelist of contact_details and include it into the parent whitelist?
Something like:
def organisation_params
my_params = [:org_reference, :supplier_reference, :org_type, :name, :org_members, :business, :contact_person]
contact_params = #get permitted params, that are defined in contact_details_controller
params.require(:organisation).permit(my_params, contact_params)
end
I don't want to workaround security, but I had already defined the permitted attributes for the contact_details and don't want to repeat it in every associated "parent" model (because it's exhausting and very prone to stupid mistakes like omitting one attribute in one of several parent models).
Use a method defined inside ApplicationController, or a shared module:
ApplicationController:
class ApplicationController
def contact_details_permitted_attributes
[:id, :contactable_id, :contactable_type, ...]
end
end
class ContactDetailsController < ApplicationController
def contact_details_params
params
.require(contact_details)
.permit(*contact_details_permitted_attributes)
end
end
class OrganisationsController < ApplicationController
def organisation_params
params
.require(:organisation)
.permit(:org_reference, ...,
contact_detail_attributes: contact_details_permitted_attributes)
end
end
Shared module:
module ContactDetailsPermittedAttributes
def contact_details_permitted_attributes
[:id, :contactable_id, :contactable_type, ...]
end
end
class ContactDetailsController < ApplicationController
include ContactDetailsPermittedAttributes
def contact_details_params
params
.require(contact_details)
.permit(*contact_details_permitted_attributes)
end
end
class OrganisationsController < ApplicationController
include ContactDetailsPermittedAttributes
def organisation_params
params
.require(:organisation)
.permit(:org_reference, ...,
contact_detail_attributes: contact_details_permitted_attributes)
end
end
Rails has even dedicated directories for shared modules, concerns inside app/controllers and app/models; indeed, in your case you should use app/controllers/concerns
I don't see why not. In your ApplicationController you could have
def contact_attributes
[:id, :contactable_id, :contactable_type, :phone, :fax,
:mail, :state, :province, :zip_code, :street, :po_box,
:salutation, :title, :last_name, :first_name, :description]
end
Then in your organisation_params
def organisation_params
my_params = [:org_reference, :supplier_reference, :org_type, :name, :org_members, :business, :contact_person]
params.require(:organisation).permit(*my_params, contact_detail_attributes: contact_attributes)
end
In some other location you might do...
def contact_params
params.require(:contact).permit(*contact_attributes)
end

Rails 4 Strong Params Error

I am using rails 4. I have a model that uses validation, but does not store any records. It is only used for a web contact form that sends an email.
I am trying to use strong parameters with this controller/model. Currently I am getting a nomethoderror on my new action. Any ideas? I think it is something to do with my model not being a full blown model.?
Code slimmed down for easy viewing.
model:
class Message
include ActiveModel::Model
include ActiveModel::ForbiddenAttributesProtection
end
controller:
class MessagesController < ApplicationController
def new
#message = Message.new
end
private
def project_params
params.require(:message).permit(:name, :email, :content)
end
end
Your project_params needs to be renamed to message_params since you want to allow message in your MessagesController and not project.
Please try:
class MessagesController < ApplicationController
def new
#message = Message.new
end
private
def message_params
params.require(:message).permit(:name, :email, :content)
end
end
Update:
Also, although you've mentioned "code slimmed down for easy viewing", I should add that you also need to define att_accessor for those permitted attributes as follows:
class Message
include ActiveModel::Model
include ActiveModel::ForbiddenAttributesProtection
attr_accessor :name, :email, :content
end
Please see Louis XIV's answer in this question: "Rails Model without a table"

Resources