Update Action with no show view - ruby

I have an Item model that I do not need a separate show view for. Instead, when the item is updated I would like to return the user to the index. When the form is submitted to edit an item, you get an error like this : No route matches [PUT] "/items/1"
Here is the routes file
Order::Application.routes.draw do
root to: 'static_pages#home'
resources :static_pages
resources :customers
resources :demands
resources :items, only: [:new, :create, :destroy, :index, :edit]
end
Here is the controller
class ItemsController < ApplicationController
def index
#items = Item.all
end
def new
#item = Item.new
end
def create
#item = Item.new(params[:item])
if #item.save
flash[:success] = "Item saved!"
redirect_to items_path
else
render new_item_path
end
end
def destroy
Item.find(params[:id]).destroy
redirect_to items_path
end
def edit
#item = Item.find(params[:id])
end
def update
#item = Item.find(params[:id])
if #item.update_attributes(params[:item])
redirect_to 'items#index'
flash[:success] = "Item updated!"
else
render 'edit'
end
end
end
Here is the model
class Item < ActiveRecord::Base
attr_accessible :name, :price
validates :name, presence: true
VALID_PRICE_REGEX = /^[+-]?[0-9]{1,3}(?:,?[0-9]{3})*\.[0-9]{2}$/
validates :price, presence: true, format: {with: VALID_PRICE_REGEX}
end

You're missing the update action for items in your routes file.
resources :items, only: [:new, :create, :destroy, :index, :edit]
should be
resources :items, only: [:new, :create, :destroy, :index, :edit, :update]
or, more concisely,
resources :items, except: [:show]

Related

Changing URL in the web page

How could i change the URL address while i'm moving from one tab to another tab within the same page? Where i want to change the code either in the routes.rb or in controller?
routes.rb:
Rails.application.routes.draw do
resources :dashboard, only: [:index]
resources :profile do
collection do
patch 'update_profile'
patch 'change_password'
end
end
devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' }
root 'dashboard#index'
end
My current url is localhost:3000/profile, now when i select update_profile tab i need the url to be localhost:3000/profile/update_profile without rendering the new page
controller code:
class ProfileController < ApplicationController
before_action :set_user, only: %i[index update_profile]
def index
#address = if #user.address
#user.address
else
Address.new
end
end
def update_profile
respond_to do |format|
if #user.update(user_params)
format.html { redirect_to profile_index_path, notice: 'Profile was successfully updated.' }
else
format.html { render :index }
end
end
end
def change_password
#user = current_user
if #user.update_with_password(user_password_params)
redirect_to root_path
else
render "index"
end
end
private
def set_user
#user = User.find(current_user.id)
end
def user_params
params.require(:user).permit(:name)
end
def address_params
params.require(:user).permit(address: %i[area state country])
end
def user_password_params
params.require(:user).permit(:password, :password_confirmation, :current_password)
end
end

Rails 4: comment partial not rendering

Trying to display comments for photo, photo belongs to profile. html does not render.
The pertinent code:
routes.rb
resources :profiles do
resources :photos do
resources :comments do
resources :comments
end
end
end
comments/_comment.html.haml
= comments.each do |comment|
%li
= comment.body
\-
%small Submitted
= #{time_ago_in_words(comment.created_at)}
= semantic_form_for [#profile, #photo, comment, Comment.new] do |f|
= f.inputs do
= f.input :body, placeholder: "Add a Reply"
%br/
= f.actions do
= f.action :submit, :as => :input, label: "Reply"
%ul
- render partial: 'comments/comment', locals: {comments: comment.comments}
models/photo.rb
class Photo < ActiveRecord::Base
belongs_to :profile
has_many :comments, as: :commentable, :dependent => :destroy
end
models/comment.rb
class Comment < ActiveRecord::Base
belongs_to :profile
belongs_to :commentable, polymorphic: true
has_many :comments, as: :commentable, :dependent => :destroy
end
models/profile.rb
class Profile < ActiveRecord::Base
belongs_to :user
has_many :photos, :dependent => :destroy
has_many :comments, :dependent => :destroy
end
app/controllers/phtos_controller.rb
class PhotosController < ApplicationController
before_action :set_photo, only: [:show, :edit, :update, :destroy]
before_action :set_profile
load_and_authorize_resource
def index
#photos = Photo.where(:profile => #profile)
end
def show
end
def new
#photo = Photo.new(:profile => #profile)
end
def edit
end
def create
#photo = Photo.new(photo_params.merge(:profile_id => #profile.id))
respond_to do |format|
if #photo.save
format.html { redirect_to [#profile, #photo], notice: 'Photo was successfully created.' }
format.json { render :show, status: :created, location: #photo }
else
format.html { render :new }
format.json { render json: #photo.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #photo.update(photo_params)
format.html { redirect_to [#profile, #photo], notice: 'Photo was successfully updated.' }
format.json { render :show, status: :ok, location: #photo }
else
format.html { render :edit }
format.json { render json: #photo.errors, status: :unprocessable_entity }
end
end
end
def destroy
#photo.destroy
respond_to do |format|
format.html { redirect_to profile_photos_url, notice: 'Photo was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_photo
#photo = Photo.find(params[:id])
end
def set_profile
#profile = Profile.find(params[:profile_id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def photo_params
params.require(:photo).permit(:description, :attachment)
end
end
/app/views/photos/show.html.haml
= render partial: "layouts/sub_header", locals: {heading: #photo.profile.name + "'s", sub_heading: "photo", current_bread_crumb: #photo.profile.name + "'s photo", include_crumbs: true}
/ Intro Content
.row
.col-md-6
= image_tag #photo.attachment.url(:large), :class => "img-responsive"
.col-md-6
%p
%h2 About this photo...
= simple_format(#photo.description)
,
/ /.row
%h3 Comments
= semantic_form_for [#profile, #photo, Comment.new] do |f|
= f.inputs do
= f.input :body, :as => :text
= f.actions do
= f.action :submit, :as => :input
%ul
- render partial: 'comments/comment', locals: {comments: #photo.comments}
- if current_user == #profile.user
= link_to 'Edit', edit_profile_photo_path(#profile, #photo)
|
= link_to 'Back', :back
Data is being inserted into the database (except the profile_id, but I will save that for another post). I manually updated the profile_id in the db to make see if it was just a data integrity issue, still nothing.
I have tried moving the resources around in the routes.rb, I have tried refactoring the views to load the collection directly without the partial, nothing seems to work.
Additionally, if I comment out the partial and use this code I do see comment bodies on the page, so it is definitely something I am doing wrong in the call to the partial or inside the partial itself.
%ul
- #photo.comments.each do |comment|
= comment.body
I cannot seem to crack this one and I know it isn't magic, but I clearly not seeing something.
Thanks for any help!
Change show.html.haml to:
%ul
- render 'comments/comment', locals: {comments: #photo.comments}
Reason being, is that you can't render a view within a view, so the above will assume you are looking for a partial named _comment.html.haml within the comments folder.
Thanks Marc and Jarvis for all your help, I still don't know why that wasn't working, but looking at the ActionView::PartialRender at api.rubyonrails.org I found that this does work...
- #photo.comments.each do |comment|
= render partial: 'comments/comment', locals: { comment: comment }
I basically have to do the iterating myself even though clearly in the guide Marc referenced it said I should be able to do what I had written.
Oh well, on to the next problem.
Thanks again!

undefined method `activation_digest=' for #<User:0x007fe3810ceba0> Michael Hartl's book

I am working through Michael Hartl's Rails book and I am about halfway through chapter 10-working on account activation.
I had everything working with the mailers but then when I tried to add a new user, I got the following error message: "undefined method `activation_digest=' for #"
I have been trying to follow along in the book the best that I can. I have my users_controller.rb here:
class UsersController < ApplicationController
before_action :logged_in_user, only: [:index, :edit, :update]
before_action :correct_user, only: [:edit, :update]
def new
#user = User.new
end
def index
#users = User.paginate(page: params[:page], :per_page => 10)
end
def show
#user = User.find(params[:id])
end
def create
#user = User.new(user_params)
if #user.save
#user.send_activation_email
flash[:info] = "Please check your email to activate your account."
redirect_to root_url
else
render 'new'
end
end
def update
#user = User.find(params[:id])
if #user.update_attributes(user_params)
else
render 'edit'
end
end
def edit
#user = User.find(params[:id])
end
#confirms if a user is logged in
def logged_in_user
unless logged_in?
store_location
flash[:danger] = "Please Log In."
redirect_to login_url
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
end
Here is my Model/user.rb:
class User < ActiveRecord::Base
attr_accessor :remember_token, :activation_token
before_save :downcase_email
before_create :create_activation_digest
before_save { self.email = email.downcase }
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\-.]+\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 },
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
has_secure_password
validates :password, length: { minimum: 6 }
# Returns the hash digest of the given string.
def User.digest(string)
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
BCrypt::Engine.cost
BCrypt::Password.create(string, cost: cost)
end
#Returns a random token
def User.new_token
SecureRandom.urlsafe_base64
end
#Remembers a user in the database for use in persistent sessions
def remember
self.remember_token = User.new_token
update_attribute(:remember_digest, User.digest(remember_token))
end
#Returns true if the given token matches the digest
def authenticated?(remember_token)
return false if remember_digest.nil?
BCrypt::Password.new(remember_digest).is_password?(remember_token)
end
#forgets a user
def forget
update_attribute(:remember_digest, nil)
end
private
# Converts email to all lower-case.
def downcase_email
self.email = email.downcase
end
# Creates and assigns the activation token and digest.
def create_activation_digest
self.activation_token = User.new_token
self.activation_digest = User.digest(activation_token)
end
end
The routes I have this:
root 'static_pages#home'
get 'sessions/new'
get 'users/new'
get 'help' => 'static_pages#help'
get 'about' => 'static_pages#about'
get 'contact' => 'static_pages#contact'
get 'signup' => 'users#new'
get 'login' => 'sessions#new'
post 'login' => 'sessions#create'
delete 'logout' => 'sessions#destroy'
resources :users
resources :account_activations, only: [:edit]
Please let me know if anything more is needed to be seen. I do have my App up on Github under the name sample_app, my username is ravenusmc.
Looking at your project on Github, your User model doesn't have an activation_token or activation_digest column, nor does the model define them as attributes.
Your User model is trying to write to these columns in the User#create_activation_digest function which is most likely causing the issue.
You'll need to write a migration to add those columns to your User model or add them is attributes (ie attr_accessor) if they are not meant to be persisted.

Stack level too deep or unknown attribute: password_confirmation

I'm working on a web app that has users model. You either sign up or try the app and be a 'guest'. I had the sign up functionality working well until I added the guest option. I based on Railscast to do this (http://railscasts.com/episodes/393-guest-user-record) and that's when I ran into troubles
Here is my user model code
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation
has_many :bookings
has_one :account, dependent: :destroy
# before_save :downcase_email, allow_nil: true
before_save :create_remember_token
validates_presence_of :name, :email, :password, :password_confirmation, unless: :guest?
validates_uniqueness_of :email, case_sensitive: false , allow_blank: true
validates :name, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, format: { with: VALID_EMAIL_REGEX }, unless: :guest?
validates :password, length: { minimum: 6 }, unless: :guest?
def downcase_email
{ |user| user.email = email.downcase }
end
# has_secure_password
# override has_secure_password to customize validation until Rails 4.
require 'bcrypt'
attr_reader :password, :password_confirmation
include ActiveModel::SecurePassword::InstanceMethodsOnActivation
##def to_param
## "#{id}.#{name.parameterize}"
##end
def self.new_guest
new { |u| u.guest = true }
end
def name
guest ? "Guest" : name
end
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
end
and here is my User Controller code:
class UsersController < ApplicationController
before_filter :signed_in_user, only: [:edit, :update]
before_filter :correct_user, only: [:edit, :update]
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def create
#user = params[:user] ? User.new(params[:user]) : User.new_guest
if #user.save
sign_in #user
#user.create_account.accountPlan = "Free"
##flash[:success] = "Welcome to the HighTide!"
redirect_to #user
else
render 'new'
end
end
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
if #user.update_attributes(params[:user])
#flash[:success] = "Profile updated"
sign_in #user
redirect_to #user
else
render 'edit'
end
end
private
def correct_user
#user = User.find(params[:id])
redirect_to(root_path) unless current_user?(#user)
end
def admin_user
redirect_to(root_path) unless current_user.admin?
end
end
you may notice some code is commented out. I wasn't able to store in the database a user without an email (and for have a quick and dirty thing working now I comment the callback before_save, I also might add that I use the guidelines of Michael Hartl tut)
What happens is, when I run this code I get a unknown attribute: password_confirmation error, but when I comment out
require 'bcrypt'
attr_reader :password, :password_confirmation
include ActiveModel::SecurePassword::InstanceMethodsOnActivation
and use has_secure_password instead
I get a stack level too deep
I haven't figured out what to do

Hartls Chapter 11: undefined method `following_user_path'

I am trying to get through the last and final chapter of the Hartl tutorial, but keep getting the below error for multiple tests across all specs. The tests started to fail as soon as I entered in the following/followers behavior into my code. Can anyone see where I'm going wrong?
ActionView::Template::Error:
undefined method `following_user_path'
Here's an example of a spec that is failing:
describe "visiting the following page" do
before { visit following_user_path(user) }
it { should have_in_title('Sign in') }
end
Here's the extracted source from _stats.html.erb (line #3):
<% #user ||= current_user %>
<div class="stats">
<a href="<%= following_user_path(#user) %>">
<strong id="following" class="stat">
<%= #user.followed_users.count %>
</strong>
following
</a>
<a href="<%= followers_user_path(#user) %>">
<strong id="followers" class="stat">
<%= #user.followers.count %>
</strong>
followers
</a>
</div>
routes.rb
SampleApp::Application.routes.draw do
resources :users do
member do
get :following, :followers
end
end
resources :sessions, only: [:new, :create, :destroy]
resources :microposts, only: [:create, :destroy]
resources :relationships, only: [:create, :destroy]
root to: 'static_pages#home'
match '/signup', to: 'users#new'
match '/signin', to: 'sessions#new'
match '/signout', to: 'sessions#destroy', via: :delete
match '/help', to: 'static_pages#help'
match '/about', to: 'static_pages#about'
match '/contact', to: 'static_pages#contact'
end
users_controller.rb
class UsersController < ApplicationController
before_filter :signed_in_user,
only: [:index, :edit, :update, :destroy, :following, :followers]
before_filter :correct_user, only: [:edit, :update]
before_filter :admin_user, only: :destroy
def show
#user = User.find(params[:id])
#microposts = #user.microposts.paginate(page: params[:page])
end
def new
if signed_in?
redirect_to root_path, notice: "Already signed in."
else
#user = User.new
end
end
def create
if signed_in?
redirect_to root_path, notice: "Already signed in."
else
#user = User.new(params[:user])
if #user.save
sign_in #user
flash[:success] = "Welcome to the Sample App!"
redirect_to #user
else
render 'new'
end
end
end
def edit
end
def update
if #user.update_attributes(params[:user])
flash[:success] = "Profile updated"
sign_in #user
redirect_to #user
else
render 'edit'
end
end
def index
#users = User.paginate(page: params[:page])
end
def destroy
user = User.find(params[:id])
if (current_user == user) && current_user.admin?
flash[:error] = "Cannot delete own admin account."
else
user.destroy
flash[:success] = "User destroyed."
end
redirect_to users_url
end
def following
#title = "Following"
#user = User.find(params[:id])
#users = #user.followed_users.paginate(page: params[:page])
render 'show_follow'
end
def followers
#title = "Followers"
#user = User.find(params[:id])
#users = #user.followers.paginate(page: params[:page])
render 'show_follow'
end
private
def correct_user
#user = User.find(params[:id])
redirect_to(root_path) unless current_user?(#user)
end
def admin_user
redirect_to(root_path) unless current_user.admin?
end
end
user.rb
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation
has_secure_password
has_many :microposts, dependent: :destroy
has_many :relationships, foreign_key: "follower_id", dependent: :destroy
has_many :followed_users, through: :relationships, source: :followed
has_many :reverse_relationships, foreign_key: "followed_id",
class_name: "Relationship",
dependent: :destroy
has_many :followers, through: :reverse_relationships, source: :follower
before_save { |user| user.email = email.downcase }
before_save :create_remember_token
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
validates :password, length: { minimum: 6 }
validates :password_confirmation, presence: true
def feed
microposts
#Micropost.where("user_id = ?", id)
end
def following?(other_user)
relationships.find_by_followed_id(other_user.id)
end
def follow!(other_user)
relationships.create!(followed_id: other_user.id)
end
def unfollow!(other_user)
relationships.find_by_followed_id(other_user.id).destroy
end
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
end
rake routes
following_user GET /users/:id/following(.:format) users#following
followers_user GET /users/:id/followers(.:format) users#followers
users GET /users(.:format) users#index
POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
sessions POST /sessions(.:format) sessions#create
new_session GET /sessions/new(.:format) sessions#new
session DELETE /sessions/:id(.:format) sessions#destroy
microposts POST /microposts(.:format) microposts#create
micropost DELETE /microposts/:id(.:format) microposts#destroy
relationships POST /relationships(.:format) relationships#create
relationship DELETE /relationships/:id(.:format) relationships#destroy
root / static_pages#home
signup /signup(.:format) users#new
signin /signin(.:format) sessions#new
signout DELETE /signout(.:format) sessions#destroy
help /help(.:format) static_pages#help
about /about(.:format) static_pages#about
contact /contact(.:format) static_pages#contact
spec_helper.rb
require 'rubygems'
require 'spork'
Spork.prefork do
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rspec/autorun'
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
RSpec.configure do |config|
config.mock_with :rspec
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = true
config.infer_base_class_for_anonymous_controllers = false
end
end
Spork.each_run do
end
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rspec/autorun'
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
RSpec.configure do |config|
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = true
config.infer_base_class_for_anonymous_controllers = false
config.order = "random"
config.include Rails.application.routes.url_helpers
end
Also, this is my first time posting here, so excuse me if I'm not posting things correctly. And please let me know if there's any other useful information I should include. Thanks!
Unfortunately one cannot just call route methods in tests. You can add it though. Check to see if you have this code below in your spec_helper.rb file.
Rspec.configure do |config|
# The line below should be in the file, if not add it.
config.include Rails.application.routes.url_helpers
end
EDIT: Your spec_helper.rb file should look like this
require 'rubygems'
require 'spork'
Spork.prefork do
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rspec/autorun'
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
RSpec.configure do |config|
config.mock_with :rspec
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = true
config.infer_base_class_for_anonymous_controllers = false
config.include Rails.application.routes.url_helpers
end
end
Spork.each_run do
end
EDIT AGAIN: Spork is a nifty little tool used for running tests. Long story short if you have a lot of tests, it takes awhile. Spork helps ease that by making the tests quicker. Once you get more familiar with testing I suggest you take a look at it.

Resources