Strong params, unpermitted parameters - ruby

I'm having an issue with strong parameters.
My permuted parameters are:
def post_params
params.require(:post).permit(:content, :user_id, :topic_id).merge(:user_id => get_user.id)
end
The parameters being passed are:
{"utf8"=>"✓",
"authenticity_token"=>"5+OEnLgihamJC37BSn4r/spoiRmccJzHhe6eaeC2Fuc=",
"post"=>{"topid_id"=>"10",
"content"=>"awfawfaw"}}
And the create function is:
def create
post = Post.new(post_params)
if post.valid? && post.save
redirect_to :controler => :topic, :action => :show, :topic => post.topic.id
end
end
That is the error in the console. I want to know why it is not permitting topic_id.

You have a typo in your permitted params:
what you have is:
def post_params
params.require(:post).permit(:content, :user_id, :topic_id).merge(:user_id => get_user.id)
end
and It should be:
def post_params
params.require(:post).permit(:content, :user_id, :topid_id).merge(:user_id => get_user.id)
end
But it depends on your model what name of attribute you have in your model. Either you have to change in the form in typo in the form, or either you have to change everywhere else.

Related

How do i add default data in rails strong params?

Lets say if i want to generate and set default password for user while creating them in admin.
and i want to do something like this,
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :password=> #default_generated_password, :password_confirmation => #default_generated_password)
end
I am using sorcery for User Authentication.
I am having a feeling that this is completely wrong way, But how do i do it?
You want to use reverse_merge (appeared in rails 5.1) or with_defaults (alias appeared in rails 5.2)
def user_params
params
.require(:user)
.permit(:first_name, :last_name, :email, :password, :password_confirmation)
.with_defaults(password: #default_generated_password, password_confirmation: #default_generated_password)
end
Merge them in after
params
.require(:user)
.permit(:first_name, :last_name)
.merge(password: #default_generated_password, password_confirmation: #default_generated_password)
Or if you need it just in one action (create for example)
def create
# password generation code...
# ...
#user = User.new(user_params.merge(password: #default_generated_password, password_confirmation: #default_generated_password))
if #user.save
redirect_to ...
else
flash[:error] = "Did not save"
render :new
end
end
private
def user_params
params.require(:user).permit(:first_name, :last_name)
end

How do I get Devise 3.4 to permit Parameters Rails 4.2

Suggestions on how to improve this question are welcome
I added 3 things to the Devise user after generating it.
t.integer "role"
t.string "firstname"
t.string "lastname"
At User Signup these parameters are permitted and user is created correctly.
When a user tries to edit their account the "firstname" and "lastname" values can be changed fine but when a user tries to change their role on their /users/edit page, no error is given, flash says "account updated successfully" but the role value have not changed.
From /log/development.log showing all 3 parameters as unpermitted, if this really is the case I don't know why the other two can be updated.
Parameters: {"utf8"=>"✓", "authenticity_token"=>"LnVPFFJKV+RtnB21ZUGr4HF1siVcEuT/BRXaLVkch1nWQXiGRFVGhdWchlQSZ9A7mFgKX2njEjCbqR4CHp5hmQ==", "user"=>{"role"=>"worker", "firstname"=>"asdfDe Wet", "lastname"=>"Blomerus", "email"=>"dewet#blomerus.org", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "current_password"=>"[FILTERED]"}, "commit"=>"Update"}
[1m[36mUser Load (0.8ms)[0m [1mSELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT 1[0m [["id", 6]]
[1m[35mUser Load (0.4ms)[0m SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 6]]
Unpermitted parameters: role, firstname, lastname
Redirected to http://localhost:3000/
Completed 302 Found in 84ms (ActiveRecord: 1.5ms)
/config/initializers/devise_permitted_parameters.rb
module DevisePermittedParameters
extend ActiveSupport::Concern
included do
before_filter :configure_permitted_parameters
end
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << [:firstname, :lastname, :role]
devise_parameter_sanitizer.for(:account_update) << [:firstname, :lastname, :role]
end
end
DeviseController.send :include, DevisePermittedParameters
Relevant parts of /app/controllers/users_controller.rb
def update
#user = User.find(params[:id])
if #user.update_attributes(secure_params)
redirect_to users_path, :notice => "User updated."
else
redirect_to users_path, :alert => "Unable to update user."
end
end
private
def secure_params
params.require(:user).permit(:role, :firstname, :lastname)
end
The update action never runs, I can completely comment it out and nothing changes.
This is what works for me with devise:
I change the users/registrations_controller.rb
class Users::RegistrationsController < Devise::RegistrationsController
before_action :configure_permitted_parameters, only: [:create]
before_filter :configure_account_update_params, only: [:update]
def create
super
end
# GET /resource/edit
def edit
super
end
# PUT /resource
def update
super
end
# DELETE /resource
def destroy
super
end
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) do |u|
u.permit(:first_name, :last_name, :user_name, :email, :password, :password_confirmation, :avatar, :avatar_cache)
end
end
def configure_account_update_params
devise_parameter_sanitizer.for(:account_update)do |u|
u.permit(:first_name, :last_name, :user_name, :email, :password, :password_confirmation, :current_password, :avatar, :avatar_cache)
end
end
I don't define any update action in the users_controller.rb . It is not needed. Also, I don;t use any type of module that you are defining and it works fine.

Padrino Admi - Omniauth - Can't Access Restricted Space after Successful Login

I primarily come from a PHP and ASP.NET background. Recently I got involved with Ruby and am starting an interesting relationship with Padrino. Not too much like Rails and not too less like Sinatra.
I am making first serious application using Padrino and it didn't take long to get stuck and would appreciate your help.
The issue with what I believe is with Padrino Admin. I am trying make users login to my website using Facebook and Omniauth.
I have been following this tutorial: Padrino and Omniauth Overview.
The application is hosted at Heroku.
Result: On Facebook login, an account is crated ( in the database ). But when I reach the restricted area, I get redirected back to the login page.
Here is what I have.
app.rb
module PDeen
class App < Padrino::Application
register Padrino::Admin::AccessControl
register SassInitializer
register Padrino::Rendering
register Padrino::Mailer
register Padrino::Helpers
enable :sessions
# get '/' do
# "Welcome to me # internet"
# end
use OmniAuth::Builder do
provider :facebook, 'xxxx', 'yyyy'
# provider :facebook, 'app_id', 'app_secret'
end
set :login_page, "/login" # determines the url login occurs
access_control.roles_for :any do |role|
role.protect "/profile"
role.protect "/admin" # here a demo path
end
# now we add a role for users
access_control.roles_for :users do |role|
role.allow "/profile"
end
get :index do
'Hi'
end
get :login do
slim :'index'
end
get :profile do
content_type :text
current_account.to_yaml
end
get :destroy do
set_current_account(nil)
redirect url(:index)
end
get :auth, :map => '/auth/:provider/callback' do
auth = request.env["omniauth.auth"]
# account = Account.find_by_provider_and_uid(auth["provider"], auth["uid"]) ||
# Account.create_with_omniauth(auth)
#
account = User.first( :provider => auth["provider"], :uid => auth["uid"] )
if ! account.nil?
set_current_account(account)
redirect :existing
end
if account.nil?
# Create account
account = User.new
account.uid = auth['uid']
account.name = auth['name']
account.provider = auth['provider']
account.email = auth['user_info']['email'] if auth['user_info']
account.role = 'users'
account.save
end
set_current_account(account)
#redirect "http://" + request.env["HTTP_HOST"] + url(:profile)
redirect :new
end
get :existing do
'existing'
end
get '/session/test' do
session[:test] = 'This is a test'
end
get '/session/print' do
"You saved: #{session[:test]}"
end
end
end
User.rb
class User
include DataMapper::Resource
# property <name>, <type>
property :id, Serial
property :name, String
property :email, String
property :role, String
property :uid, String
property :provider, String
end
What happens >>
List item
I go to [server]/profile ~> redirects to [server]/login
I click on Facebook ~> takes to the page to accept the app ~> redirects back to the app
I go to [server]/profile ~> redirects to [server]/login
I thought that sessions are not working. In the time I was working on my first PHP app, I had similar session based issue. But it turned out to be that it wroks. That is where the [server]/session/test and [server]/session/print came in.
When I login to the Padriono console in Heroku and use User.all I see the entry.
I also see that the user gets authenticated. Some thing has to be with `
I checked the Padrino admin Accounts modal. I think the important parameters would be id and role.
Have I done some thing wrong?
Thanks in advance. Any help is highly appreciated.
After going through the Padrino source code, I noticed that it is expecting the Account class for Padrino Admin authentication.
I was assuming, I could make any class and just use it. But for the moment, I have modified the Account.rb modal and instead of using User ( above ) I used Account.
I write this just as I got it resolved, so the validation section of the modal is commented out.
class Account
include DataMapper::Resource
include DataMapper::Validate
attr_accessor :password, :password_confirmation
# Properties
property :id, Serial
property :name, String
property :surname, String
property :email, String
property :crypted_password, String, :length => 70
property :role, String
property :uid, String
property :display_name, String
property :provider, String
# # Validations
# validates_presence_of :email, :role
# validates_presence_of :password, :if => :password_required
# validates_presence_of :password_confirmation, :if => :password_required
# validates_length_of :password, :min => 4, :max => 40, :if => :password_required
# validates_confirmation_of :password, :if => :password_required
# validates_length_of :email, :min => 3, :max => 100
# validates_uniqueness_of :email, :case_sensitive => false
# validates_format_of :email, :with => :email_address
# validates_format_of :role, :with => /[A-Za-z]/
# Callbacks
before :save, :encrypt_password
##
# This method is for authentication purpose
#
def self.authenticate(email, password)
account = first(:conditions => ["lower(email) = lower(?)", email]) if email.present?
account && account.has_password?(password) ? account : nil
end
##
# This method is used by AuthenticationHelper
#
def self.find_by_id(id)
get(id) rescue nil
end
def has_password?(password)
::BCrypt::Password.new(crypted_password) == password
end
private
def password_required
crypted_password.blank? || password.present?
end
def encrypt_password
self.crypted_password = ::BCrypt::Password.create(password) if password.present?
end
end
Note that just after the role, I added 3 more fields namely uid, display_name and provider.
It seems as though, uid provder and role are what is important for the access control.
The controller / route are the same except for one minor change. That is the Model name.
if account.nil?
# Create account
account = Account.new
Would be interesting to use own modal with Omniauth and Padrino Admin helpers. But for the moment, this is great!

Uninitialized constant (NameError) when using FactoryGirl in module

Here's the error I'm getting when I try to run my tests with RSpec:
C:/Ruby193/lib/ruby/gems/1.9.1/gems/activesupport-3.2.11/lib/active_support/infl
ector/methods.rb:230:in `block in constantize': uninitialized constant User (Nam
eError)
I'm trying to run FactoryGirl with RSpec but without Rails. Here are the files that take part in the testing:
user_spec.rb
require 'spec_helper'
module Bluereader
describe User do
describe 'login' do
user = FactoryGirl.build(:user)
end
describe 'logout' do
end
describe 'create_account' do
end
describe 'delete_account' do
end
end
end
spec/spec_helper
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..'))
$LOAD_PATH.unshift(File.dirname(__FILE__))
require 'rspec'
require 'lib/bluereader'
require 'factory_girl'
FactoryGirl.find_definitions
spec/factories.rb
require 'digest/sha1'
FactoryGirl.define do
sequence(:username) { |n| "user-#{n}" }
factory :user do
username
encrypted_password Digest::SHA1.hexdigest('password')
full_name 'John Doe'
logged_in_at Time.now
logged_out_at 0
end
end
At this point I know that the factories.rb file is being loaded (I tried with the moronic print-debugging). When I remove the user = FactoryGirl.build(:user) line from user_spec.rb I get no errors (and the normal RSpec feedback telling me there are no tests, but no errors). If you are interested, here's my model:
require 'digest/sha1'
module Bluereader
class User < ActiveRecord::Base
has_many :categories, :foreign_key => :user_id
has_many :news, :foreign_key => :user_id
has_many :settings, :foreign_key => :user_id
attr_reader :full_name
class << self
def login(username, password)
encrypted_password = Digest::SHA1.hexdigest(password)
if not User.exists?(:username => username, :encrypted_password => encrypted_password)
user_id = User.id_from_username(username)
update(user_id, :logged_in_at => Time.now, :logged_out_at => 0)
end
end
def logout
update(current_user.id, :logged_out_at => Time.now)
end
def validate_account(username, password, full_name)
if username.empty? or password.empty or full_name.empty?
return 'Please fill in all the fields.'
end
if User.exists?(:username => username)
return 'That username is already in use.'
end
unless username =~ /^\w+$/
return 'Username field should contain only letters, numbers and underscores.'
end
''
end
def create_account(username, password, full_name)
encrypted_password = Digest::SHA1.hexdigest(password)
User.create(:username => username,
:encrypted_password => encrypted_password,
:full_name => full_name,
:logged_in_at => Time.now,
:logged_out_at => 0)
end
def delete_account
current_user.destroy
end
private
def id_from_username(username)
user = where(:username => username).first
user.nil? ? 0 : user.id
end
def current_user
where(:logged_out_at => 0).first
end
end
end
end
SOLUTION
The problem was that the class User was in a module, here's the solution:
factory :user, class: Bluereader::User do
You need to require the rails environment in your spec helper file. Add the following to spec/spec_helper.rb:
require File.expand_path("../../config/environment", __FILE__)
Update
Even if you're not using Rails, you'll still need to require the models in your spec helper.
Taken from the bottom of the question
The problem was that the class User was in a module, here's the solution:
factory :user, class: Bluereader::User do
For anyone clumsy like me, you may have FactoryGirl in your code where you meant to have FactoryBot

Ruby Sinatra + Sequel constraint error handling

What is the right way to handle exceptions coming from the model in Sequel? Particularly the thing I'm running into is when the unique constraint is applied to the login. The exception in this case appears to be coming from SQLite itself instead of Sequel which means it's not getting handled by "errors".
This is the error I'm getting after trying to create a user with a "non-unique" login:
Sequel::DatabaseError at /user/create
SQLite3::ConstraintException: column login is not unique
file: database.rb location: close line: 97
Here is my abbreviated code:
require 'sinatra'
require 'sequel'
DB.create_table :users do
primary_key :id
String :login, :key => true, :length => (3..40), :required => true, :unique => true
String :hashed_password, :required => true
String :salt
DateTime :created_at, :default => DateTime.now
end
class User < Sequel::Model
# password authentication code
end
get '/user/create' do
slim :user_create
end
post '/user/create' do
user = User.new
user.login = params['login']
user.password = params['password']
if user.save
'User created'
else
tmp = []
user.errors.each do |e|
tmp << (e.join('<br/>'))
end
tmp
end
end
You probably want to use the validation_helpers plugin and use validates_unique :login inside the validate method.
Add the code below to handle sequel errors in sinatra.
The error block in sinatra will handle any errors thrown in one of your routes. You can specify the type of error in the first line in order to only handle those types of errors.
error Sequel::Error do
e = env['sinatra.error']
content_type :json
status(400)
return {
message: e.message
}.to_json
end
If you wanted to handle all errors, you would insert the following block of code.
error Exception do
e = env['sinatra.error']
content_type :json
status(400)
return {
message: e.message
}.to_json
end
You can combine many of these blocks so that you are handling different types of errors differently.
First - use validation plugin
# models/account.rb
Sequel::Model.plugin :validation_helpers
class Account < Sequel::Model
def validate
super
validates_unique :login
end
end
Next - handle error in app
# app.rb
...
begin
Account.create
rescue => e
# do what you need
end
...

Resources