Undefined local variable or method for class - ruby

What did I miss?
ERROR: undefined local variable or method `feedback' for #<#<Class:0x007f66dc8dca30>:0x007f66dc8cee80>
Migration:
class CreateFeedbacks < ActiveRecord::Migration
def change
create_table :feedbacks do |t|
t.references :user
t.text :body
t.timestamps
end
end
end
Model:
class Feedback < ActiveRecord::Base
attr_accessible :body, :user
belongs_to :user
end
Controller:
class FeedbacksController < ApplicationController
before_action :authenticate_user!
def index
#feedback = Feedback.all
end
def new
#feedback = Feedback.new
end
def create
#user = User.find(params[:user])
#feedback = #user.feedbacks.create(params[:feedback])
respond_to do |format|
if #feedback.save
format.html { redirect_to #user, notice 'Comment was successfully created.' }
format.json { render json: #feedback, status: :created, location: #feedback }
else
format.html { render action: "new" }
format.json { render json: #feedback.errors, status: :unprocessable_entily }
end
end
end
User model:
has_many :feedback
Routes:
resources :feedbacks
resources :users do
resources :feedbacks
end

Firstly, it helps a lot to style your question and code correctly as well as mark your files (routes.rb, controllers, models correctly). Else it would be very difficult for readers to understand your question and spot issues with your code. You can refer to https://meta.stackoverflow.com/editing-help for the styleguide/ markdown.
Secondly, it looks like your routes.rb are incorrect - but again, this could be due to your formatting. Based on your question, it looks like your routes are:
resources :feedbacks
resources :users do
resources :feedbacks
end
end
When it should be:
resources: users do
resources: feedbacks
end
Thirdly, your seem to have a typo in your model (feedback instead of feedbacks. That is:
class User < ActiveRecord::Base
has_many :feedbacks
end
class Feedback < ActiveRecord::Base
belongs_to :user
end
Lastly, do add specifics and what exactly you ran that caused the error. E.g. did you run something in console, what page did you load?

Related

Paperclip don't save on database

I am using the following Gems:
'paperclip'
'aws-sdk', '~> 2.3'
I would like to save images to S3, but am unable to get them to save.
model/user.rb
class User < ApplicationRecord
# This method associates the attribute ":avatar" with a file attachment
has_attached_file :avatar, styles: {
thumb: '100x100>',
square: '200x200#',
medium: '300x300>'
}
# Validate the attached image is image/jpg, image/png, etc
validates_attachment_content_type :avatar, :content_type => /\Aimage\/.*\Z/
end
migration
class AddAvatarToUsers < ActiveRecord::Migration[5.1]
def self.up
add_attachment :users, :avatar
end
def self.down
remove_attachment :users, :avatar
end
end
controllers/users_controller.rb
class UsersController < ApplicationController
def edit
#user = User.find_by(id: params[:id])
end
def update
#user = User.find(params[:id])
if #user.update(user_params)
flash[:notice] = "Edit successfully"
redirect_to("/users/#{#user.id}")
end
end
private
def user_params
params.require(:user).permit(:avatar, :name, :email, :phone_number, :description, :college_name)
end
end
Why is the image avatar not being stored in the database?
Should I add any database columns? What should I do? I would appreciate any input to help me solve this problem.
Paperclip must be configured to use S3 to store the objects (images). It will store metadata associated with these in the database, but not the images.
See Paperclip Documentation
You will also need to set an access policy for your S3 bucket, and define on the User model how they are to be addressed from S3.

Undefined Method 'add_product ' for model object

I think my error is kind of silly, but it's keeping me stuck. I'm following the Agile Web Development with Rails 4 and developing the app Depot from it. I'm getting a
undefined method `add_product' for #<Cart:0x007f2ee4cfb8f8>
error. My code is as follows,
class LineItemsController < ApplicationController
def create
find_cart
product = Product.find(params[:product_id])
byebug
#line_item = #cart.add_product(product.id) // line with error
#line_item.product = product
respond_to do |format|
if #line_item.save
format.html {redirect_to #line_item.cart,
notice: 'Line Item was succesfully created'}
format.json {render json: #line_item,
status: :created, location: #line_item}
else
format.html {render action: "new"}
format.json {render json: #line_item.errors,
status: "Unprocessable Entry"}
end
end
end
end
Cart.rb
class Cart < ActiveRecord::Base
has_many :line_items, dependent: :destroy
def add_products(product_id)
current_item = line_items.find_by_product_id(product_id)
if current_item
current_item.qunatity += 1
else
current_item = line_items.build(product_id: product_id)
end
current_item
end
end
Also, I want to know, how can a method from different model be directly called into a separate controller ?
The object cart has value, I have debugged to make sure, as well as the error line also has the object present.
Thanks for your help.
I found the mistake, it was a typo I made in Cart.rb. I had named the method add_product's' and was calling add_product in the controller.

Set user_id for nested_attribute in devise registration before user exists

The idea is simple. I require a nested attribute tag for user registration. tag requires a user_id.
the view
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: {role: :form}) do |f| %>
<%= f.fields_for :tags, resource.tags.build do |a| %>
<%= a.text_field :tagname %>
<% end %>
<% end %>
tag migration
class CreateTags < ActiveRecord::Migration
def change
create_table :tags do |t|
t.string :tagname
t.references :user, index: true
t.timestamps
end
add_index :tags, :tagname, unique: true
end
end
the tag model
class Tag < ActiveRecord::Base
belongs_to :user
validates_presence_of :user_id
validates_uniqueness_of :tagname
end
the user model
class User < ActiveRecord::Base
has_many :tags, autosave: true, dependent: :destroy
accepts_nested_attributes_for :tags
end
strong parameters
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(
:tags_attributes => [:id, :user_id, :tagname]
) }
The save feature is untouched at the moment. The form passes the nested attribute :tagname just fine. But I've been unable to get the "would be" user_id from resource.
I've already looked for hours online for any answer to this. None has appeared, but the idea that the nested attribute should be saved after the initial user object is saved sounds like a workable solution. But then it's no longer handled as a nested attribute.
Help is appreciated! Thanks!
Solution
Alright I solved it. I bastardised my devise registrations controller a bit, but it works.
First I removed user_id verification from my tag model.
class Tag < ActiveRecord::Base
belongs_to :user
validates_uniqueness_of :tagname
end
I then proceeded with modifying the devise registration controller.
def create
build_resource(sign_up_params)
# added code begins here
#tag = nil
#tag.define_singleton_method(:valid?) {false}
if params["user"].has_key? "tags_attributes"
#tag = Tag.new(params["user"].delete("tags_attributes").values.first)
if #tag.valid?
resource_saved = resource.save # original line of code
else
resource.errors.add(*#tag.errors.first)
flash.delete :tagname_error
set_flash_message :alert, :tag_taken if is_flashing_format?
end
else
set_flash_message :alert, :need_tag if is_flashing_format?
end
# end added code
yield resource if block_given?
if resource_saved
if resource.active_for_authentication?
set_flash_message :notice, :signed_up if is_flashing_format?
sign_up(resource_name, resource)
# This is where current_user has been created and resource.id == current_user.id
# begin added code
#tag.user_id= resource.id
# end added code
respond_with resource, location: after_sign_up_path_for(resource)
else
set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_flashing_format?
expire_data_after_sign_in!
respond_with resource, location: after_inactive_sign_up_path_for(resource)
end
else
clean_up_passwords resource
#validatable = devise_mapping.validatable?
if #validatable
#minimum_password_length = resource_class.password_length.min
end
respond_with resource
end
end
I've defined :tag_taken and :need_tag in my devise locales file for translations of the error string.
And everything works!
For the record this is in addition to the existing code in the question.

App with Accounts and Users - Devise user can't create additional users

Using Rails 3.1.3 with Devise 1.5.3. My app has accounts and users. Each account can have multiple users. A user can have one role, "user" or "account_admin". Devise signup routes to accounts#new. The account and an initial account_admin user are created simultaneously. Got this working as described here (although things have evolved some since then).
An account_admin signs should be able to create additional users in that account. That's where I'm running into trouble: instead of creating new users, it's just redirecting to the user_path (users#show) page with the message "You are already signed in." (user_path is my overridden after_sign_in_path.)
This article asks a similar question. The answer suggests a separate namespace for admins, but since admins are part of my regular app I don't think that applies.
I've defined a complete UsersController. According to the log, GET "/users/new" renders from my "UsersController#new". However POST "/users" is intercepted by Devise and rendered from "Devise::RegistrationsController#create".
config/routes.rb
devise_for :users
devise_scope :user do
get "signup", :to => "accounts#new"
get "signin", :to => "devise/sessions#new"
get "signout", :to => "devise/sessions#destroy"
end
resources :users
resources :accounts
app/controllers/users_controller.rb
class UsersController < ApplicationController
before_filter :authenticate_user!
load_and_authorize_resource # CanCan
...
def new
# CanCan: #user = User.new
end
def create
# CanCan: #user = User.new(params[:user])
#user.skip_confirmation! # confirm immediately--don't require email confirmation
if #user.save
flash[:success] = "User added and activated."
redirect_to users_path # list of all users
else
render 'new'
end
end
...
end
I've tried overriding the Devise controller, thinking I could tell it to use my users#create action if the user is already signed in. The log tells me it is using my controller ("Processing by RegistrationsController#create as HTML"), but it doesn't seem to execute its code. I've commented out my custom actions and just left in the logger lines, but I don't get my logging messages. And in spite of super being commented out, the behavior doesn't change--it still redirects with "You are already signed in."
config/routes.rb
devise_for :users, :controllers => {:registrations => "registrations"}
app/controllers/registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
def new
logger.info "Custom RegistrationsController: new"
super
end
def create
logger.info "Custom RegistrationsController: create"
# super unless user_signed_in?
# render "users#create"
end
def update
super
end
end
What am I missing? How can I let the account_admin user create additional users?
The main issue is that Devise was intercepting the POST "/users" (and a few other routes). Found this workaround to allow my Users controller handle those routes: change the devise_for to skip registrations, then add back in the routes for which Devise normally defines aliases:
routes.rb
devise_for :users, :skip => [:registrations]
devise_scope :user do
get "signup", :to => "accounts#new"
get "signin", :to => "devise/sessions#new"
get "signout", :to => "devise/sessions#destroy"
get "cancel_user_registration", :to => "devise/registrations#cancel"
post "user_registration", :to => "users#create"
get "new_user_registration", :to => "accounts#new"
get "edit_user_registration", :to => "users#edit"
end
resources :users
resources :accounts
Never figured out why the Devise controller override wasn't working.
A user on this thread pointed out the devise_invitable gem which might be an interesting alternative.
This is how I ended up getting this to work with my setup (Devise tied to my User model -- no separate Editor/Admin model):
class UsermakersController < ApplicationController
before_action :authenticate_user!
def new
#user = User.new
end
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to users_path, notice: 'User was successfully created.' }
format.json { render :show, status: :created, location: #user }
else
format.html { render users_path }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
private
def user_params
userParams = params.require(:user).permit(:name, :email)
end
end
From here, when you want to add a new User as another User, simply call the Usermakers#new url in your form, e.g., I have this at the bottom of my Users index page:
<%= link_to 'Add User', new_usermaker_path, id: 'new_user_link' %>
And the Usermakers form looks like:
= simple_form_for #user, url: usermakers_path, html: {multipart: true} do |f|
=f.error_notification errors: true
= f.input :name
= f.input :email
%p
= f.button :submit, 'Create User', class: 'button'
Of course, you'd need to add a dummy new.html.erb file which simply renders _form.html.erb to use this.
Just add the new and create methods to your routes.rb file (whether by resources :usermakers, or more specific routes) and you should be good to go. Hope this helps!

Confusing about a function :before_filter

I have following controller:
class CarsController < ApplicationController
autocomplete :user, :name
before_filter :require_user, :except => [:my_action]
def index
end
...
def my_action
end
end
I want to allow to see all actions in this controller only for log in users - this works me fine. But the action my_action I would like to have accesible for everyone - also for a people who are not log in.
I tried to set :before_filter with the :except parameter, also with the :only parameter, but nothing works me... The app always want for me to be log in... what I am doing still wrong?
EDIT: require_user from application_controller.rb:
def require_no_user
logger.debug "ApplicationController::require_no_user"
if current_user
#store_location
flash[:warning] = "You must be logged out to access this page"
redirect_to account_url
return false
end
end
Use
skip_before_filter :require_user, :only => [:my_action]

Resources