Pass two params in a Rails Controller - ruby-on-rails-4

I'm working on a project that requires a third party (not a registered user of my application) to follow an email link to update a document. I've created a :token column for each entry, and have it successfully appended to the email link using:
edit_form_url(:id => #form.id, :token => #form.token)
My problem is trying to reference the additional param in my controller using this code:
def edit
#form = Form.find(params[:id],[:token])
redirect_to pages_error_path if #form.sign.present?
end
When using the above code, I get a Couldn't find all Forms with 'id': (193, token) (found 1 results, but was looking for 2) error. Can anyone help me figure out what I'm doing wrong?

It seems I may have solved my own problem, posting it for Google and error checks:
def edit
#form = Form.find_by(token: params[:token], id: params[:id])
redirect_to pages_error_path if #form.sign.present?
end

Related

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!!!

Pundit::AuthorizationNotPerformedError attempting to adapt microposts to Devise/Pundit

I'm new to Rails and I'm working through Michael Hartl's excellent Rails Tutorial for a second time, this time I'm trying to adapt the chapter 11 and chapter 12 microposts to a simple Devise/Pundit application I'm working on. I am able to create microposts through the seed file and display them, but I'm getting an authorization error with Pundit when I actually try to create a new post through the site. The error I'm getting is:
Pundit::AuthorizationNotPerformedError in MicropostsController#create
My Microposts Controller looks like this:
class MicropostsController < ApplicationController
before_action :authenticate_user!
after_action :verify_authorized
def create
#micropost = current_user.microposts.build(micropost_params)
if #micropost.save
flash[:success] = "Micropost created!"
redirect_to current_user
else
#feed_items = []
flash[:danger] = "Unable to create micropost!"
end
end
def destroy
end
private
def micropost_params
params.require(:micropost).permit(:content)
end
end
I'm thinking that do not have the authorization set up properly for the 'create' action, but I'm not sure exactly how it should be set. I do not have a policy for Pundit for Microposts. I tried adding a simple one but it didn't change anything. I'm learning to put all these pieces together, would someone point me in the right direction?
There is one after action filter verify_authorized because of which you are getting this error. If you have created a policy for the create action then use that to get rid of the error.

undefined method `model_name' for #<User:XXXXXXXX>

I have a dashboard containing 2 partials. One partial works fine and does what its suppose to (bill). The other partial is setup similar to bill but wont work(request). When I look at my log it shows that the tenant(user) is being queried, also, the 1st partial is queried but the 2nd partial doesn't query. when I went to my dashboard controller and changed the instance of the partial to (Request.new) it works but I can't seem to get it to work right thru the controller. I don't want to have the method in the model. I am using mongoid.
SO here is my render in the dashboard...
<%= render partial: "request", locals: {request: #request} %>
In the partial I have...
<%= form_for [:tenants, request] do |f| %>
And on the dashboard controller I have...
def show
#dashboard = current_tenant
#bill = current_tenant.bill || current_tenant.build_bill
#request = current_tenant.request || current_tenant.build_request
end
(if I change #request = Request.new it works fine but I know that's not right)
The bill partial works and the dashboard finds the tenant but I keep getting
"undefined method `request' for #
Any idea of what I am missing? I compared the bill controller to the request controller and I cant find any differences. When I put the Model.new into the dashboard controller it works but I know this isn't right, its as if the app wont recognize the Request controller...
The error is saying it doesn't recognize "request" method.
Also here is my controller for request...
class Tenants::RequestsController < ApplicationController
before_filter :authenticate_tenant!
def index
#requests = Request.all
end
def show
#request = Request.find(params[:id])
end
def create
if #request = current_tenant.create_request(authorization_params)
redirect_to tenants_dashboard_path, :notice => "#{request.manager_name} has been Authorized!"
else
redirect_to tenants_dashboard_path, :error => "#{request.manager_name} has NOT been Authorized, please try again."
end
end
def edit
end
def update
if current_tenant.request.update_attributes(authorization_params)
redirect_to tenants_dashboard_path, :notice => "You have approved #{request.manager_name} to review your report"
else
redirect_to tenants_dashboard_path, :notice => "#{request.manager_name} is NOT allowed to review your report"
end
end
def destroy
#request = Request.find(params[:request_id])
name = #request.name
if #request.destroy
flash[:notice] = "\"#{name}\" was successfully removed from your profile."
redirect_to #dashboard
else
flash[:error] = "There was an error deleting this managers access."
render :show
end
end
Well it looks like
current_tenant.request has an issue. That means that the method is not available. Assuming you're not trying to access the http request , then you have an issue with the request method.
So your issue is with how you defined the request method (maybe in your model). e.g. is it a class method or a instance method etc.
Without knowing your goal, that's the general answer I can give you. Creating a Request.new could be right depending on your goal, but if your goal is to call the request method, you must make it available to current_tenant
One controller shouldn't be calling your other controller as you have suggested...

Understanding Rails/Twitter On-click tweet on behalf of user

As preface, I've followed through some tutorials (i.e. Michael Hartl's) though I'm still fairly novice. Forgive any cloudy terminology.
I am trying to build a simple application in Rails 4 that does the following:
User logs into application (currently working with sign-in-with-twitter link and routing)
get "/auth/:provider/callback" => "sessions#create"
get "/signout" => "sessions#destroy", :as => :signout
Once <% if current_user %> is true, I have the view rendering a partial where there will be a list of simple buttons. When the user clicks a button I want the application to tweet on behalf of the current_user a preset string. Ideally, I'd do this all in ruby/rails.
These button functions are where I'm getting hung up. I've read a fistful of documents but there seem to be a lot of conflicting and old answers. Here's a quick list of the ones I think are closest, though not explicit about sending a tweet from a simple button/link in a view:
http://www.sitepoint.com/ruby-social-gems-twitter/
http://richonrails.com/articles/sending-a-tweet-to-twitter
Some call for controllers, a more robust oauth setup (which I have bundle installed and connected to the dev.twitter application, though not fleshed out beyond keys), and whatever else. It's got me turned around and I'm not yet good enough to synthesize all the information. Any help and direction would be great. Below are some other files in the app that might be helpful.
class SessionsController < ApplicationController
def create
auth = request.env["omniauth.auth"]
user = User.find_by_provider_and_uid(auth["provider"], auth["uid"]) || User.create_with_omniauth(auth)
session[:user_id] = user.id
redirect_to root_url, :notice => "Hi!"
end
def destroy
session[:user_id] = nil
redirect_to root_url, :notice => "Bye!"
end
end
And omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
provider :twitter, '_priv', '_priv'
end
Eep! I'm the author of the second link (RichOnRails). Did you take a look at the example app included with the tutorial? It does almost exactly what you want. If the tweets are hard coded you could approach it in a couple of different ways. If you take a look at the tweets controller, you'll see it takes a parameter called 'message'. Any message passed to that create method will tweet as the current user.
def create
current_user.tweet(twitter_params[:message])
end
The easiest (but not necessarily best) way to adapt this to fit your needs is to have a form for each tweet, and do a hidden field with the message you wish to tweet. The button becomes a submit for that particular form (you can add remote: true if you want to keep the page from refreshing, then use a bit of javascript to update the UI elements). Hope this helps.

Signed-in users have no reason to access the new and create (is there a better answer)

This is the answer to one common question asked by many users and for those who are using Rails 4.0 and following the updated tutorial,
Since answer to this question has been updated with the newer version of Railstutorial(rails 4.0) by Michael Hartl's
I have found in almost every post related to this question that the solution to this problem is to add these lines in users_controller.rb file
before_filter :signed_in_user_filter, only: [:new, :create]
.
.
.
def signed_in_user_filter
if signed_in?
redirect_to root_path, notice: "Already logged in"
end
end
but this solution only works for localhost:3000/signup but will not do anything to localhost:3000/signin since its the solution given with respect to railstutorial(Rails 3.0).And its not going to work for those who are following Railstutorial(Rails 4.0).
For referrence to this question you can see this post Railstutorial:exercise 9.6
So,for Rails 4.0, I have found solution to this while looking at the /config/routes.rb file
match '/signup', to: 'users#new', via: 'get'
match '/signin', to: 'sessions#new', via: 'get'
Those who are using Rails 4.0 and following the tutorial, you need to edit "new" method in users_controller.rb file for restricting the access to /signup path( when user is already logged-in) and "new" method in sessions_controller.rb file for restricting the access to /signin path when already logged-in.
You need to add these lines to "new" method in users_controller.rb file
def new
if signed_in?
redirect_to root_url
flash[:notify] = '!Please log-out before Signing-up'
else
#user = User.new
end
end
And add these lines to "new" method in sessions_controller.rb file
def new
if signed_in?
redirect_to root_url
flash[:error] = 'Already logged-in'
else
end
end
This solution has worked for me, as i am also using Rails 4.0(railstutorials)