Routing to Controller in ActiveAdmin 1.0.0 - ruby-on-rails-4

rake routes gives the output
POST /admin/users(.:format) admin/users/new
But where is the new action executed? The /admin/user is the registered resource. There are no actions. However creating a new user through the standard AA form puts my user in the database but which controller is used?
UPDATE:
I want to create a new user using ActiveAdmin with a password and store the hashed password using devise. The new action works in my normal user controller which i test through rails console
#user=User.create(params.permit(:name, :phone, :active, :password_digest
#user.password = Devise.friendly_token
So far i hacked the action in the AA user.rb resource like this:(basically the same statements encapsulated in controller do...)
controller do
def new
#user.password = Devise.friendly_token
#user=User.create(params.permit(:name, :phone, :active, :password_digest
The Issue i have now it that the user gets saved in my db but with an unshashed password.(?)
The live demo and the documentation are a bit short on detailed information or examples on this issue.

ActiveAdmin uses inherited resources gem for the default controller actions. If you want to overwrite the new controller action, you can overwrite it in your activeadmin resource code like so:
ActiveAdmin.register User do
controller do
def new
super #use the default methods and response block
#user.activate! #if you want to add some methods
end
end
end

The ActiveAdmin Gem creates a Admin::UsersController on the fly, based on the configuration of you admin/user.rb

Related

Routes in Rails SAML IdP

I'm trying to get this gem to work with Rails 4 application that will serve as a SAML identity provider.
The thing that is confusing me is the routes and the template I assume should be rendered. In the gem controller, there is this:
def new
render template: "saml_idp/idp/new"
end
My routes are just the basic setup from the example, which I assume should match the action in my custom controller that inherits from the gem controller.
I have this in my controller.
class SamlIdpController < SamlIdp::IdpController
def idp_authenticate(email, password)
true
end
def idp_make_saml_response(user)
encode_SAMLResponse("you#example.com")
end
end
And my routes.rb file:
get '/saml/auth' => 'saml_idp#new'
get '/saml/metadata' => 'saml_idp#show'
So, what am I missing here? There should be a view rendered, instead I'm getting No Route Matches errors. Thanks.
As per Doc, I think you missed including SamlIdp::IdpController module
please include SamlIdp::IdpController rather than excluding.
Hope, It will work.
The new update for saml_idp gem wants to include SamlIdp::Controller as a module. And the controller class can inherit from ApplicationController
In your case it will be:
class SamlIdpController < ApplicationController
include SamlIdp::Controller
end

Ruby on Rails Pundit's current_user is nil in integration test

I'm using the gems pundit and devise. I have a delete link that only shows up if you are an admin. I have an integration test that I would like to verify that the delete link only shows up for admins.
test 'comment delete link shows when it should' do
log_in_as #admin
get movie_path(#movie)
assert_select 'a[href=?]', movie_comment_path(comments(:one), #movie.id)
end
My test_helper.rb looks like this:
...
class ActiveSupport::TestCase
...
def log_in_as(user, options = {})
password = options[:password] || 'password'
if integration_test?
post user_session_path, 'user[email]' => user.email, 'user[password]' => user.password
else
Devise::TestHelpers.sign_in user
end
end
private
# Returns true inside an integration test.
def integration_test?
defined?(post_via_redirect)
end
end
The response.body looks all right, but indeed there is no delete link. There is one when I run the development server and visit the page myself. I've narrowed this down to the current_user that pundit uses in the policies is being passed in with a value of nil. This is my comment_policy.rb:
class CommentPolicy
attr_reader :current_user, :comment
def initialize(current_user, model)
#current_user = current_user
#comment = model
end
def create?
if #current_user
#current_user.member? or #current_user.content_creator? or #current_user.moderator? or #current_user.admin?
end
end
def destroy?
if #current_user
#current_user == #comment.user or #current_user.moderator? or #current_user.admin?
end
end
end
As a closing remark, I've heard that Rails 5 has opted for integration tests instead of controller tests as we know them from Rails 4 for the default type of tests to be generated for our controllers. If this is the case, devise would be a heck of a lot more useful out of the box when using Rails 5 if the sign_in/sign_out helpers that work in controller tests were made to work in integration tests as well. But would I still have this issue of pundit not knowing what current_user is? I'm assuming this all works fine in controller tests because the current_user is scoped to controllers? Any and all light shed on this topic is much appreciated, but I would really like to figure out how to get integration tests to work with this setup because I have about a billion I want to write right now.
Not that it totally matters, but does it need to be using current_user in the policy or can it just use user in the policy. By this I mean according to the elabs/pundit README on Github I would just use #user and user everywhere instead of current_user. Read the README if I confused you.
Additionally the nil for current_user typically occurs when you don't have a valid CSRF token for your request. When you do this on the website manually by going to localhost:3000 or w/e you are first performing a get on the login path before doing the post on the login path with your credentials. In your integration test I don't seem to see where you are performing that get in order to get the CSRF for your session.
Hope this helps!!!

Rails 4 Dynamically Generate an Extra Public-Facing URL on Create

I have a Rails app that stores stock photos in each project. Upon creating a project, I want the app to not only create the url for the project that we will view internally, which is projects#show,i.e. /projects/4 but I also want it to create another URL that we can show to the client that will be a little different. It will allow the to approve the photos, etc. I want the url to be something like /projects/st53d where the end of the url will be a random number generated with random_string = SecureRandom.urlsafe_base64(5)
This way, I can pass this url to the clients and they can view all the photos in the project and approve the ones they want us to use, but cannot change or view the other internal stuff we have on the standard product show page
Currently, I have added a client_url column to the Project model and I was thinking of generating the random number within the Project#create method and then saving it to the project's client_url column. This way I can loop through all client urls and make sure I did not generate a duplicate. But I cannot figure out how to do the route creation part.
i have yet to do the part where I check if it is random but I know how to do that, just not the route creation.
I was thinking I needed to create a new method which I named show_client and somehow create a route for that in my config/routes.rb file
class ProjectsController < ApplicationController
before_action :authenticate_user!, only: [:show,:index]
def create
#project = Project.create(project_params)
#project.creator = current_user.email
require 'securerandom'
random_string = SecureRandom.urlsafe_base64(5)
#project.client_url = random_string
#project.save
redirect_to #project
end
def show_client
#project = Project.find(params[:id])
#photos = #project.photos
end
This seems like more of a roles issue. You could check out something like CanCanCan. If you only need two kinds of users, you could also just add a boolean column for admin to your user table. The url extension doesn't seem to matter in the scope of your problem. If you want to use a different view for the visiting the user show page, something in the show action like:
unless current_user.admin?
redirect_to client_show(current_user.id)
end
I was able to figure it out.
I created the client_url column in the database and upon creating a project, in the create method of the projects_controller, I generated a random base64 number and assigned it to project.client_url
in routes.rb i did:
get 'projects/clients/:client_id' => 'projects#clients', as: 'projects_client'
in my projects_controller.rb:
def clients
#project = Project.where(client_id: params[:client_id])
end
then the link to that route is:
<%= link_to 'Client Version', projects_client_path(#project.client_url) %>

Rails Admin actions in model

I have a sensitive civic involvement Rails app. In it's Rails Admin I have disabled the delete and bulk_delete actions.
In rails_admin.rb I have something like
RailsAdmin.config do |config|
config.actions do
dashboard # mandatory
index # mandatory
new
export
show
edit
# delete
# bulk_delete
end
end
How can I override this behaviour for specific models, for example, SitePosts? I have tried using the "rails_admin do" block in the model, but it is not working obviously.
rails_admin do
configure :site_post do
actions do
new
show
edit
delete
end
end
end
You can use the only method for enabling actions for specific models. For instance, in your rails_admin.rb:
config.actions do
dashboard # mandatory
index # mandatory
new
delete do
only SitePost
end
end
The only and except methods are documented in the wiki under Base action.

Generating a unique URL with tokens in Rails 4 for an external form response

I have a 'Feedback' model whereby a user should be able to request feedback on his/her job performance. I have written basic actions for creating a new feedback request, and the mailer for sending the request to the provider (person who will respond with feedback).
I would like advice from the community on implementing the following:
Once a new feedback request is created, the email that is sent should contain a link to a form where the provider can input his feedback on the users performance.
The feedback provider should not be required to log-in or sign-up in any way (i.e. completely external to the application).
Once submitted, feedback from the provider should be captured in the
system.
Now, I have the following ideas to implement it, but am not sure if this is the best way to proceed:
Generate a unique token upon the creation of a new feedback request. Something like this: Best way to create unique token in Rails?.
The token should then be entered into 'feedbacks' table.
Mailer should then generate variable (e.g. #url) which generates link to another controller (let's say 'external_feedback' and action which does not require log-in (e.g. no before_filter :authenticate_user! from Devise).
That URL should contain a parameter with the token for the specific feedback request.
The action should be to update the 'feedback' request and a form generated with simple_form.
The whole thing is similar to responding to a questionnaire or survey (like Survey Monkey).
After some research I believe the Friendly ID gem may be useful here. I was also reading Section 8 of http://guides.rubyonrails.org/form_helpers.html and perhaps I need to implement an authenticity_token in the formal sense. What I am really looking for is:
Is the above approach the generally correct way to go about doing this?
If so, any specifics on how you would implement it (with or without Friendly ID)?
Do you know of any gems that exist for generating such URLs/tokens?
Thank you in advance. I am now including the current state of model and controller details:
feedback.rb
# == Schema Information
#
# Table name: feedbacks
#
# id :integer not null, primary key
# user_id :integer
# p_first_name :string(255)
# p_last_name :string(255)
# p_email :string(255)
# goal_id :integer
# u_comment :text
# p_comment :text
# created_at :datetime
# updated_at :datetime
#
class Feedback < ActiveRecord::Base
belongs_to :user
belongs_to :goal
has_many :feedback_attributes
validates_presence_of :p_first_name, :p_last_name, :p_email, :goal_id
end
And this is my mailer:
class FeedbackMailer < ActionMailer::Base
def feedback_request(user, feedback)
#user = user
#feedback = feedback
#url = 'http://thisistheexampleurlforfeedback'
mail(to: #feedback.p_email, subject: "#{#user.first_name} #{#user.last_name} has requested your feedback", from: #user.email)
end
end
Add a token field to the feedback model with an index and add a callback to populate it on create e.g.
feedback.rb
before_create :add_token
private
def add_token
begin
self.token = SecureRandom.hex[0,10].upcase
end while self.class.exists?(token: token)
end
now add a new route for the providers feedback
resources :feedbacks do
get 'provider'
put 'provider_update' # you might not need this one, if you are happy to use update
end
In your controller make sure they don't get rejected by devise
before_filter :authenticate_user!, except: [:provider, :provider_update]
...
def provider
#feedback = Feedback.find_by token: params[:token]
end
then in the app/views/feedback/provider.html.haml you can use url in simple_form to send it to the correct update location and only provide the input that they should see.
f.inputs :p_comment
Now update your mailer.
#url = provider_feedback_url(#feedback, token: #feedback.token)
You could do something similar to this using friendly id but you would still need to create some sort of unique slug and then use Feedback.friendly.find instead. I think you would want to combine it with a token to ensure it's still the provider giving the feedback - so the only benefit would really be hiding the true id/count. I think you should update p_* fields to provider_* so that the next dev knows what's in it - it's not the 90s!