Getting Data from API (ok 200 Response Undefined Method 'id') - ruby-on-rails

I got the below to work and call up membership data based on current_user.id (See 200 Ok response) this shows up in my logs.
GET https://api-e1.authrocket.com/v1/memberships?user_id=usr_0vKhXTr0K1bz6kUipKNnjD
-> 200 (103.4 ms)
NoMethodError (undefined method `id' for #<NCore::Collection:0x007f50c82a7e50>):app/controllers/directory/categories_controller.rb:13:in `index'
I was using current_user.id which worked.
#directory_category.user_id = current_user.id
Trying to change it so it grabs the user's membership.id
#directory_category.user_id = membership_info.id
The full create statement I'm working with.
# Create
def create
#directory_category = Directory::Category.new(directory_category_params)
#directory_category.user_id = membership_info.id
if #directory_category.save
redirect_to directory_categories_path, notice: 'Category was successfully created.'
else
render :new
end
end
# Directory Category Index
def index
#directory_categories = Directory::Category.where(user_id: membership_info.id)
end
My attempt, which does say 200 ok getting current_user id and putting it at the end AuthRocket::Membership.all statement like below:
def current_user
#_current_user ||= AuthRocket::Session.from_token(session[:ar_token]).try(:user)
end
def membership_info
AuthRocket::Membership.all user_id: current_user.id
end
https://authrocket.com/docs/api/memberships

It looks like your
def membership_info
AuthRocket::Membership.all user_id: current_user.id
end
method is actually returning a collection and not a single item. if you change it to
def membership_info
AuthRocket::Membership.all(user_id: current_user.id).first
end
or whichever record you actually want, you should stop this error from raising.

Related

Rails 4 - pundit - how to write if statement to check user permissions

I'm trying to learn how to use pundit with my Rails 4 app.
I have a potential use policy. The potential use table has an attribute called :user_id.
I want users to be permitted to update instances if they created them. I'm trying to figure out how to get the update action to work.
My current attempts are shown below.
class PotentialUsePolicy < ApplicationPolicy
attr_reader :user, :record
def initialize(user, record)
#user = user
#record = record
end
def index?
true if user.is_admin?
end
def show?
true
end
def new?
true
end
def create?
new?
end
def update?
if #user.id == #potential_use.user_id
# if user.id == potential_use.user_id
true
else
false
end
end
def destroy?
update?
end
def edit?
true
end
def potential_use
record
end
end
When I try these, I keep getting errors saying:
undefined method `user_id' for nil:NilClass
I don't understand why I get this message. When I look in the console, I can see an entry which has a user id.
p = PotentialUse.where(project_id: 26)
PotentialUse Load (0.5ms) SELECT "potential_uses".* FROM "potential_uses" WHERE "potential_uses"."project_id" = $1 [["project_id", 26]]
=> #<ActiveRecord::Relation [#<PotentialUse id: 9, comment: "adsfsfdadfasdddxxddbbdd", project_id: 26, created_at: "2016-08-18 23:16:06", updated_at: "2016-08-24 01:06:00", user_id: 1, private_comment: false>]>
2.3.0p0 :016 >
When I look in the view (without trying to use the pundit policy, the page renders with all the right content, including the user name (which is accessed by the user_id).
The update action in my potential use controller has:
def update
authorize #potential_use
respond_to do |format|
if #potential_use.update(potential_use_params)
format.html { redirect_to #project, notice: 'Potential use was successfully updated.' }
format.json { render :show, status: :ok, location: #potential_use }
else
format.html { render #project }
format.json { render json: #potential_use.errors, status: :unprocessable_entity }
end
end
end
Can anyone see what I've done wrong?
To check if a user has permission to perform an action on a policy from a view:
<% if policy(#post).update? %>
<%= link_to "Edit post", edit_post_path(#post) %>
<% end %>
Your error is because you call #potential_use.user_id but #potential_use is never declared in the policy class. You defined potential_use as a method, but in that method you call record, instead of #record.
So, to fix it you should call potential_use instead of #potential_use and change the method to:
def potential_use
#record
end
Or simply, call #record.user_id instead of #potential_use.user_id.
Besides, as you can see in the Pundit readme, when you inherit from ApplicationPolicy, you don't need to declare:
attr_reader :user, :record
def initialize(user, record)
#user = user
#record = record
end
As it is already in the parent class.
You access the authorized objects with your accessors. In your example you probaly called
authorize #potential_use
in your controller update action. The update? method on your controller would look like this:
def update?
user.id == record.user_id
end

Rails4: losing form validation errors while using `redirect_to` in controller

I've been trying to fix this for a while but haven't gotten anywhere yet. Would appreciate if someone could let me know how how this can be done, or if there is any way i can use the render method to do this instead (currently preserves errors but redirects to wrong path as mentioned below...)
I have a custom route for form which I am trying to redirect back when there are validation errors:
get "clubs/sign_up/:plan_id", to: "clubs#new", as: :new_membership
below is what I have so far in my controller along along with some comments regarding other steps I have tried
clubs_controller.rb
def create
#membership = Membership.new(membership_params)
if #membership.save
redirect_to root_path
else
flash[:error] = "Please check form errors:"
redirect_to new_membership_path(session[:membership_plan_id]) #errors lost
# render action: 'new', plan_id: 'silver' # <<<Preserves errors but breaks path, renders: localhost:3000/clubs instead of .../clubs/sign_up/:plan_id
# session[:membership_errors] = #membership.errors #<<< Doesn't wotk either, getting a cookie overflow error when trying to pass errors to #new
return
end
end
def new
session[:membership_plan_id] = params[:plan_id]
#membership = Membership.new
end
Assuming plan_I'd is part of your model..
Change your render line to:
render :new
Change the rest to:
def new
session[:membership_plan_id] = params[:plan_id]
#membership = Membership.new plan_id: params[:plan_id]
end
def create
#membership = Membership.new(membership_params)
if #membership.save
redirect_to root_path
else
flash[:error] = #membership.errors.full_messages.to_sentence
render :new
end
end
And add a hidden field for plan_id in your form. The reason render goes wrong is that it does not have the param available, trying to add it to the render operation does not work hence your issue
You need to render instead of redirecting. Use the ||= operator to help here.. It's all just ruby, so something like
(..snip..)
else
flash[:error] = "Problem with form"
new
end
end
def new
session[:membership_plan_id] = params[:plan_id]
#membership ||= Membership.new
render 'new'
end

Rendering template from another controller causes NoMethodError

I'm working on a rails app that contains a Users controller and an Images controller. This is the create method in the Images controller:
def create
#image = current_user.images.build(image_params)
if #image.save
flash[:success] = "Image uploaded!"
redirect_to current_user
else
render 'users/show' #Error occurs here
end
end
Successful saves are handled fine, but if the image is too large or non-existent and 'users/show' is rendered, rails gives the error:
NoMethodError (undefined method `name' for nil:NilClass):
app/views/users/show.html.erb:1:in `_app_views_users_show_html_erb___2850090823537495038_37901140'
app/controllers/images_controller.rb:12:in `create'
I expect this happened because I hadn't initialized all the variables necessary for 'users/show' within my Images controller, so I moved the content from the show method of the Users controller to a new method in the Application controller and called it before rendering the page from Images. Here's the intitialize method:
def initialize_show
#user = User.find(params[:id])
#images = #user.images.paginate(page: params[:page])
#image = current_user.images.build if logged_in?
end
And the new create method:
def create
#image = current_user.images.build(image_params)
if #image.save
flash[:success] = "Image uploaded!"
redirect_to current_user
else
initialize_show # Called this method
render 'users/show'
end
end
Now rails is giving the error:
ActiveRecord::RecordNotFound (Couldn't find User with 'id'=):
app/controllers/application_controller.rb:6:in `initialize_show'
app/controllers/images_controller.rb:12:in `create'
What am I missing here? This is my first rails app so I appreciate the help.
ptd provided the answer in a comment above. #user wasn't getting initialized because the id param wasn't posted to images#create. Here's the solution:
def create
#image = current_user.images.build(image_params)
if #image.save
flash[:success] = "Image uploaded!"
redirect_to current_user
else
#user = current_user
initialize_show # I removed the #user initialization in this method
render 'users/show'
end
end
It looks like your template (users/show) uses something (#vars) that is not available in this case. Can you show that template code? Maybe you have something line #user.name there but this var is not initialized in case you have described...

New acts like create

In my create action, method new acts like create.
def create
#page = Page.new(params[:page].merge(:user_id => current_user.id ))
if #page.save
flash[:notice] = t("success")
redirect_to pages_path
else
render :new
end
end
ActiveRecord creates new object in database while I'm using new with params. Page.new works fine in new action in my controller. What can be the reason? There is no overridden method new and no callbacks (before_save, before_create etc) in my model. Any help would be appreciated.
UPDATE - code from debugger
.../app/controllers/pages_controller.rb:48
#page = Page.new(params[:page].merge(:user_id => current_user.id ))
(rdb:25) #page
nil
(rdb:25) n
.../app/controllers/pages_controller.rb:49
if #page.save
(rdb:25) #page
#<Page id: 80 ... >
(rdb:25) Page.last
#<Page id: 80 ... >
(rdb:25) #page.save
false
Check my inline comments..
def create
#page = Page.new(params[:page].merge(:user_id => current_user.id )) # you trigger new thats fine..
if #page.save # Notice here.. This line is triggering query on database.
flash[:notice] = t("success")
redirect_to pages_path
else
render :new
end
end
Reason (method in model which can change status in workflow):
def status=(state_name)
states = [self.current_state.to_sym]
possible_states.each {|t| states<< t[1]}
unless state_name.blank?
if states.include? state_name
process_event! state_name
end
end
end
Ugly fix
def create
#page = Page.new
if #page.update_attributes(params[:page].merge(:user_id => current_user.id )) && #page.save
flash[:notice] = t("success")
redirect_to pages_path
else
render :new
end
end
Mistake was quite silly and I'm not proud of my solution. Anyway, thanks for help:)
With an ActiveRecord class, create = new + save
https://github.com/rails/rails/blob/7edade337e968fb028b2b6abfa579120eb424039/activerecord/lib/active_record/persistence.rb#L40
Your controller code is correct. This is how a 'create' controller method should work. The problem is not there.
Are you certain you're having two models created?
The .new method you're calling with the attributes creates an activerecord object in memory that's unsaved. The .save method saves it. At the end (assuming the data is valid) you should have a single object in memory.
If you have two objects created, then there is a problem. If you have only one, then it's as it should be.
Are you having a second object created by this controller method?
The process should be:
# when GET /student/new is called, this returns an empty object to display in the form
# for the user to see.
def new
#page = Page.new
end
# When POST /page is called, the form params are passed in here.
def create
# First, generate a new page object with the params passed in.
#page = Page.new(params[:page].merge(:user_id => current_user.id ))
# Now try save the object to persist it in the database.
if #page.save
flash[:notice] = t("success")
redirect_to pages_path
else
render :new
end
end

Template not found on Rails when I just redirect

I'm making a Rails app where I have a method:
def updateAttributes_post
if logged_in?
userPlucky = User.where(:screen_name=>session[:screen_name]).all
userPlucky.each do | user |
user.update_attributes(:email => params[:emailAddr], :password=>params[:passwordStr])
if user.save
flash[:success] = "Succesfully updated attributes!"
redirect_to '/dashboard'
else
errors = Array.new()
for i in 0..user.errors.full_messages.count
errors.push(user.errors.full_messages[i])
end
session[:error] = errors
flash[:error] = "Error saving"
redirect_to '/update'
end
end
else
redirect_to root_path
end
end
which is called on a POST request. The thing is on every if I'm redirecting on both cases, but I'm still getting a Template not found`. If I add a template with the name it asks it just renders the blank template without doing nothing. What I'm doing wrong?
If no user matches (ie userPlucky is empty), you do not call any redirect_to.

Resources