I can't understand why permit_params wont work with custom create action.
For example lets take basic AdminUser resource.
By default all is working fine. We have:
ActiveAdmin.register AdminUser do
permit_params :email, :password, :password_confirmation
form do |f|
f.inputs "Admin Details" do
f.input :email
f.input :password
f.input :password_confirmation
end
f.actions
end
end
But as soon we add custom create for some reasons permit_params wont work anymore.
ActiveAdmin.register AdminUser do
permit_params :email, :password, :password_confirmation
form do |f|
f.inputs "Admin Details" do
f.input :email
f.input :password
f.input :password_confirmation
end
f.actions
end
controller do
def create
AdminUser.create(params[:admin_user])
do_some_magic_stuff_here
redirect_to backend_admin_users_path, notice: 'Custom create'
end
end
end
I got error "ActiveModel::ForbiddenAttributesError" in line "AdminUser.create(params[:admin_user])"
Tried many possible solutions and only one worked for me, but i really don't like this:
def create
AdminUser.create(params[:admin_user].permit(:email, :password, :password_confirmation))
do_some_magic_stuff_here
redirect_to admin_admin_users_path, notice: 'Custom create'
end
I can't understand why i can't get to work default way as it should work:
def admin_user_params
params.require(:admin_user).permit(:email, :password, :password_confirmation)
end
Can someone explain me please what is happening here? Any nice way to have custom actions work with permit_params?
permit_params is just part of the AA DSL that defines a method called permitted_params, which in turn is called from the create and update actions. Try this:
permit_params :email, :password, :password_confirmation
controller do
def create
#admin_user = AdminUser.create(permitted_params)
do_some_magic_stuff_here
redirect_to backend_admin_users_path, notice: "Custom create"
end
end
permit_params is really just a simpler form of the old, but still valid way of enabling strong parameters:
controller do
def permitted_params
params.permit admin_user: [:email, :password, :password_confirmation]
end
end
Been struggling with the same problem here. The most strange thing is that it works on nitrous.io box but on my production server it doesn't. I've checked and I'm using the same rails 4.2.0 version.
Regards
Fak
Related
I'm using the sign-up and login that we built with the rails tutorial as a base for a Reddit clone that I’m making. As it stands the application is functioning properly apart from the user_id in comments table is blank when I make a comment, the link_id is present and correct so I can make comments on a link. The user_id in links table is also present and correct.
I'm fairly certain that the error i've made is in the create action of comments_controller.rb but it could also be my original migration. What's confusing me (as a novice) is I had this working in it's current form once before with rails 4.1.8 and device. However, using this approach with rails 4.2.1 using the rails tutorial as a base, it doesn't work. I'm a bit new here so I hope i've formulated the post correctly and given enough information so somebody could give me some pointers as to the problem
Comment Controller
before_action :logged_in_user, only: [:create, :destroy]
def create
#link = Link.find(params[:link_id])
#comment = #link.comments.create(params[:comment].permit(:link_id, :body))
#comment.user = User.find(current_user.id)
redirect_to link_path(#link)
end
def destroy
#link = Link.find(params[:link_id])
#comment = #link.comments.find(params[:id])
#comment.destroy
redirect_to link_path(#link)
end
private
def logged_in_user
unless logged_in?
flash[:danger] = "Please log in."
redirect_to login_url
end
end
Form
app/views/links/show.html.erb
<h2 class="comment-count"><%= pluralize(#link.comments.count, "comment") %></h2>
<%= render #link.comments %>
<%= form_for([#link, #link.comments.build]) do |f| %>
<%= render 'comments/fields', f: f %>
<%= f.submit "Save Comment", class: 'btn btn-primary margin-bottom-10' %>
<% end %>
Partials
app/views/comments/_comment.html.erb
<p class="comment_body"><%= comment.body %></p>
<p class="comment_time"><%= time_ago_in_words(comment.created_at) %> Ago </p>
app/views/comments/_fields.html.erb
<%= render 'shared/comment_error_messages' %>
<%= f.label :body %>
<%= f.text_area :body, class: 'form-control' %>
Routes
config/routes.rb
resources :links do
member do
put "like", to: "links#upvote"
put "dislike", to: "links#downvote"
end
resources :comments
end
Models
app/models/link.rb
belongs_to :user
has_many :comments, dependent: :destroy
app/models/comment.rb
belongs_to :user
belongs_to :link
validates :body, presence: true
app/models/user.rb
has_many :links, dependent: :destroy
Migration
class CreateComments < ActiveRecord::Migration
def change
create_table :comments do |t|
t.integer :link_id
t.text :body
t.references :user, index: true, foreign_key: true
t.timestamps null: false
end
add_index :comments, :link_id
end
end
Hopefully that’s a good enough post and I’ve included everything you need so somebody can help me out, It's a rookie error but i can't see it. thanks in advance.
Regards
As it stands, you are currently creating a comment without saving user_id for it. Try the below code
#comments_controller.rb
def create
#link = Link.find(params[:link_id])
#comment = #link.comments.new(params[:comment].permit(:link_id, :body))
#comment.user = User.find(current_user.id)
#comment.save
redirect_to link_path(#link)
end
I have a Rails 4 app using Active Admin 1.0.0.pre1 in conjunction with pundit 0.3.0 for authorization which has worked flawlessly thus far, but I'm having trouble figuring out a good way automatically customize forms based on a user's role.
Given these models:
ActiveAdmin.register AdminUser do
permit_params do
Pundit.policy(current_admin_user, resource).permitted_attributes
end
form do |f|
f.inputs "Admin Details" do
f.input :role, as: :select, collection: [:manager, :admin]
f.input :email, as: :email
f.input :password
f.input :password_confirmation
end
f.actions
end
end
class AdminUserPolicy < ApplicationPolicy
def permitted_attributes
attributes = [:email, :password, :password_confirmation]
attributes += [:role] if user.has_role? :super_admin
attributes
end
end
I'd like for the role input to be automatically removed from the form.
One option would be something along the lines of:
permitted_attributes = Pundit.policy(current_admin_user, resource).permitted_attributes
form do |f|
f.inputs "Admin Details" do
f.input :role if permitted_attributes.include? :role
f.input :email
f.input :password
f.input :password_confirmation
end
f.actions
end
but, that approach requires the developer to remember which attributes should be checked, seems prone to forgetfulness and isn't exactly DRY. Perhaps, I am going about this the wrong way? All suggestions welcome.
Intercepting ActiveAdminForm by prepending a module that overrides input with a check against the Pundit policy seems to work well. Here is the implementation I went with:
# /lib/active_admin/permitted_active_admin_form.rb
module PermittedActiveAdminForm
def permitted_attributes
policy = Pundit.policy(current_admin_user, resource)
policy.respond_to?(:permitted_attributes) ? policy.permitted_attributes : []
end
def input(*args)
super(*args) if permitted_attributes.include? args[0]
end
end
# /config/initializers/active_admin.rb
module ActiveAdmin
module Views
class ActiveAdminForm < FormtasticProxy
prepend PermittedActiveAdminForm
end
end
end
# /app/admin/admin_user.rb
ActiveAdmin.register AdminUser do
permit_params do
resource ||= AdminUser
Pundit.policy(current_admin_user, resource).permitted_attributes
end
form do |f|
f.inputs "Admin Details" do
f.input :role, as: :select, collection: [:manager, :admin]
f.input :email, as: :email
f.input :password
f.input :password_confirmation
end
f.actions
end
end
Thanks to Andrey Deineko for starting me down the right path.
I know pundit, not active_admin. With that in mind, using the code you provided, I'll just throw an idea out there.
whitelist = Pundit.policy(current_admin_user, resource).permitted_attributes
fields = %i( role email password password_confirmation )
form do |f|
f.inputs "Admin Details" do
(fields & whitelist).each do |field|
f.input field
end
end
f.actions
end
I have a basic file upload with carrierwave:
uploaders/image_uploader.rb:
class ImageUploader < CarrierWave::Uploader::Base
include CarrierWave::RMagick
storage :file
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
end
models/event.rb:
class Event < ActiveRecord::Base
...
mount_uploader :picture, ImageUploader
end
I can upload an image with a form in the app (not the admin part) and it works fine. I see the image path in the picture field in ActiveAdmin.
But I cannot change the picture field directly in ActiveAdmin. I tried to create a new event with an image, or change an existing event. If an image was present, it stayed the same. If there were no image previously, no image were added. In short, I can view the picture field in ActiveAdmin, but I cannot change it. This is the case only for the picture field (I can change the other fields)
Note: No upload starts when I submit the form (I don't see the uploading xx% in the bottom left of chrome). I also tried other browers, same behaviour. I get no errors in the rails server console.
admin/events.rb:
ActiveAdmin.register Event do
permit_params :user_id, :category_id, :name, :date, :description, :text, :picture
# tried adding this, form still works, but image still doesn't work.
form multipart: true do |f|
f.inputs "Event details" do
f.input :category_id
f.input :name
f.input :description
f.input :picture, as: :file
end
f.actions
end
end
Why can't I change the picture field in ActiveAdmin ?
The problem was the same as in this question: File upload with Activeadmin Rails using paperclip
Changing admin/events.rb to this made the upload work:
ActiveAdmin.register Event do
permit_params :user_id, :category_id, :name, :date, :description, :text, :picture
form :html => { :enctype => "multipart/form-data" } do |f| # <--- changed
f.inputs "Event details" do
...
end
f.actions
end
end
Issue #3577 was open for this on GitHub and a PR was merged earlier today.
Currently my application is using devise and my users are required to enter a password when updating their profile.
I am working on implementing an additional field to my user's table which remembers their sidebar navigational preference (expanded or collapsed). For testing, I setup a boolean field called "menu_collapsed" which is set to "false" by default.
I am trying to have this value updated to "true" remotely when the user decides to condense the sidebar menu.
Index
<li><%= link_to('Toggle', toggle_menu_preference_user_path(#user), :method => :put) %></li>
Routes
resources :users do
member { put :toggle_menu_preference }
end
Users Controller
def toggle_menu_preference
#user = current_user
#user.menu_collapsed = !#user.menu_collapsed
#user.save
end
Application Controller
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:first_name, :last_name, :email, :account_id, :account_name, :password, :password_confirmation) }
devise_parameter_sanitizer.for(:account_update).concat([:name])
end
When I click on the link, it will process the request but I hit a wall with Devise wanting the user to include their password.
Is there a way to by pass the requirement for a password just for this user attribute?
This seems to work like a charm!
Tested on local host as well as Heroku
Application Controller (added :menu_collapsed) to sanitizer
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:first_name, :last_name, :email, :account_id, :account_name, :password, :password_confirmation) }
devise_parameter_sanitizer.for(:account_update).concat([:name, :menu_collapsed])
end
Routes
resources :users do
member { put :toggle_menu_preference }
end
User Controller
def menu_preference
#user = current_user
#user.menu_collapsed = !#user.menu_collapsed
#user.save
if #user.menu_collapsed
render :nothing => true
else
render :nothing => true
end
end
View
<%= link_to menu_preference_user_path(current_user), id: "layout-condensed-toggle", remote: true do %>
<div class="iconset top-menu-toggle-dark"></div>
<% end %>
I have this code in my application_controller.rb
before_filter :update_sanitized_params, if: :devise_controller?
before_filter :store_location
protect_from_forgery with: :exception
def update_sanitized_params
devise_parameter_sanitizer.for(:sign_up) {|u| u.permit(:email, :password, :password_confirmation, :role)}
devise_parameter_sanitizer.for(:sign_in) {|u| u.permit(:email, :password) }
end
but I still have validation errors from devise
Email can't be blank
Password can't be blank
Password can't be blank
Role is not included in the list
Devise was working fine few days ago I don't know what messed up with it I have added active_admin may be this created conflicts any help please??
Assuming that you are getting the validation errors while updating a User record.
def update_sanitized_params
devise_parameter_sanitizer.for(:sign_up) {|u| u.permit(:email, :password, :password_confirmation, :role)}
devise_parameter_sanitizer.for(:sign_in) {|u| u.permit(:email, :password) }
## Permit the attributes for account_update
devise_parameter_sanitizer.for(:account_update) {|u| u.permit(:email, :password, :password_confirmation, :role) }
end
You need to permit the attributes explicitly which you would like to be updated by specifying devise_parameter_sanitizer.for(:account_update) else they would not be passed to users table for updating.
I have solved the Problem by adding this line in user.rb
attr_accessible :email, :password, :role
and this works with gem " protected_attributes"