New to web development and have been trying to solve this for 4 days now - been through every solution here on StackOverflow but none of the answers have worked for me.
I am creating an application that allows users to upload an attachment and photo through Paperclip. Authentication and Authorization through Devise and CanCan
From a edit page, a user can click on a link to open an 'edit' page. From there he can see a form to browse and choose an image to upload. When clicking on the button, it calls the 'update' action and then renders the users show page, the image is saved to a tmp folder but does not insert to the Database.
Here is my User Model
class User < ActiveRecord::Base
has_and_belongs_to_many :roles
has_attached_file :avatar, styles: {
thumb: '50x50>',
square: '200x200#',
medium: '300x300>'
}
def role?(role)
return !!self.roles.find_by_name(role.to_s.camelize)
end
# Validate the attached image is image/jpg, image/png, etc
validates_attachment_content_type :avatar, :content_type => /\Aimage\/.*\Z/
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable, :confirmable,
:recoverable, :rememberable, :trackable, :validatable
end
User Controller
class UsersController < ApplicationController
before_action :get_user, :only => [:index, :new, :edit]
before_action :accessible_roles, :only => [:new, :edit, :show, :update, :create]
load_and_authorize_resource :only => [:show, :new, :destroy, :edit, :update]
def index
#users = User.accessible_by(current_ability, :index).limit(20)
respond_to do |format|
format.json { render :json => #users }
format.xml { render :xml => #users }
format.html
end
end
def new
respond_to do |format|
format.json { render :json => #users }
format.xml { render :xml => #users }
format.html
end
end
def show
#user = User.find(params[:id])
respond_to do |format|
format.json { render :json => #users }
format.xml { render :xml => #users }
format.html
end
rescue ActiveRecord::RecordNotFound
respond_to_not_found(:json, :xml, :html)
end
def edit
respond_to do |format|
format.json { render :json => #users }
format.xml { render :xml => #users }
format.html
end
rescue ActiveRecord::RecordNotFound
respond_to_not_found(:json, :xml, :html)
end
def destroy
#user.destroy!
respond_to do |format|
format.json { respond_to_destroy(:ajax) }
format.xml { head :ok }
format.html { respond_to_destroy(:html) }
end
rescue ActiveRecord::RecordNotFound
respond_to_not_found(:json, :xml, :html)
end
def create
#user = User.new(user_params)
if #user.save
respond_to do |format|
format.json { render :json => #users.to_json, :status => 200 }
format.xml { head :ok }
format.html { redirect_to :action => :index }
end
else
respond_to do |format|
format.json { render :text => "Could not create user", :status => :unprocessable_entity }
format.xml { head :ok }
format.html { render :action => :new, :status => :unprocessable_entity }
end
end
end
def update
if params[:user][:password].blank?
[:password, :password_confirmation, :current_password].collect{|p| params[:user].delete(p) }
else
#user.errors[:base] << "The password you entered is incorrect" unless #user.valid_password?(params[:user][:current_password])
end
respond_to do |format|
if #user.errors[:base].empty? and #user.update_attributes(user_params[:user])
flash[:notice] = "Your account has been updated"
format.json { render :json => #user.to_json, :status => 200 }
format.xml { head :ok }
format.html { render :action => :show }
else
format.json { render :text => "Could not update user", :status => :unprocessable_entity }
format.xml { render :xml => #user.errors, :status => :unprocessable_entity }
format.html { render :action => :edit, :status => :unprocessable_entity }
end
end
rescue ActiveRecord::RecordNotFound
respond_to_not_found(:json, :xml, :html)
end
private
def accessible_roles
#accessible_roles = Role.accessible_by(current_ability, :read)
end
def get_user
#user = current_user
end
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation, :avatar, :resume)
end
end
Here is the form code:
<%= form_for #user, :html => { :multipart => true } do |f| %>
<div class="field">
<%= f.label :avatar, "Photo" %>
<%= f.file_field :avatar %>
<%= f.submit "Submit" %>
</div>
<% end %>
I can not even seem to get it to display the temp image.
Any help will be much appreciated!
Show.html.erb
<%= image_tag #user.avatar.url(:medium) %>
<%= #user.email %>
Related
So I have two models : Artist and Artwork.
Artist have a :name parrameter
Artist have_many artworks and Artwork has_one Artist.
I don't understand why when I call for #artworks.artiste.name in the artworks Index I have this error :
undefined method `artist'
this is my index :
<div class="col-xs-12 col-md-6 col-xs-offset-0 col-md-offset-4 col-lg-offset-5">
<p id="notice"><%= notice %></p>
<h1><%= #artworks.artist.name %></h1>
<% #artworks.each do |artwork| %>
<div class="artwork-container">
<div class="artwork-info">
<span><%= artwork.title %></span>
<p><%= artwork.description %></p>
<span><%= artwork.price %></span>
<span><%= link_to 'Edit', edit_artist_artwork_path(:artist, artwork) %></span>
<span><%= link_to 'Destroy', artist_artwork_path(:artist, artwork), method: :delete, data: { confirm: 'Are you sure?' } %>
</span>
</div>
<div class="artwork-photo-container">
<div class="artwork-photo" style="background-image: url('<%= artwork.photo.url %>');"></div>
</div>
</div>
<% end %>
<br>
<%= link_to 'New Artwork', new_artist_artwork_path %>
</div>
this is my artwork controller :
class ArtworksController < ApplicationController
before_action :set_artwork, only: [:show, :edit, :update, :destroy]
# GET /artworks
# GET /artworks.json
def index
#artworks = Artwork.all
end
# GET /artworks/1
# GET /artworks/1.json
def show
#artwork = Artwork.find(params[:id])
end
# GET /artworks/new
def new
#artwork = Artwork.new
end
# GET /artworks/1/edit
def edit
end
# POST /artworks
# POST /artworks.json
def create
#artwork = Artwork.new(artwork_params)
respond_to do |format|
if #artwork.save
format.html { redirect_to artist_artwork_url(:artist, #artwork), notice: 'Artwork was successfully created.' }
format.json { render :show, status: :created, location: artist_artwork_url(:artist, #artwork) }
else
format.html { render :new }
format.json { render json: #artwork.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /artworks/1
# PATCH/PUT /artworks/1.json
def update
respond_to do |format|
if #artwork.update(artworks_params)
format.html { redirect_to artist_artworks_url(:artist, #artworks), notice: 'Artwork was successfully updated.' }
format.json { render :show, status: :ok, location: artist_artwork_url(:artist, #artworks) }
else
format.html { render :edit }
format.json { render json: #artwork.errors, status: :unprocessable_entity }
end
end
end
# DELETE /artworks/1
# DELETE /artworks/1.json
def destroy
#artwork.destroy
respond_to do |format|
format.html { redirect_to artist_artworks_url(:artist, #artworks), notice: 'Artwork was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_artwork
#artwork = Artwork.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def artwork_params
params.require(:artwork).permit(:title, :description, :ref, :dateof, :price, :stock, :front, :photo, artist_attributes: [ :name, :surname])
end
end
those are my 2 models:
class Artist < ActiveRecord::Base
has_many :artworks
end
class Artwork < ActiveRecord::Base
has_one :artist
accepts_nested_attributes_for :artist
has_attached_file :photo, default_url: "/images/:style/missing.png"
validates_attachment_content_type :photo, :content_type => ["image/jpg", "image/jpeg", "image/png", "image/gif"]
validates_attachment_presence :photo
validates_presence_of :title, :description, :stock, :front, :price
end
Change has_one :artist to belongs_to :artist. The reason is that has_one doesn't store an id, so the two models don't really have any association. belongs_to adds an artist_id field.
Ok so I solved the error by replacing <h1><%= #artworks.artist.name %></h1>
by <%= #artworks.first.artist %>
Thanks you
I am trying to create a page within my application that shows all listings from a specific user. I am using Devise gem for my users. i do not need/want authentication, therefore the page should be open the the general public. I have already created a "Seller" page where a seller can manage their own listings. so how can I create a link on each listing on my homepage that connects the
<p><%= "Sold by #{listing.user.name}" %></p>
the new show page for that user? thanks!
my listings_controller:
class ListingsController < ApplicationController
before_action :set_listing, only: [:show, :edit, :update, :destroy]
before_filter :authenticate_user!, only: [:seller, :new, :create, :edit, :update, :destroy]
before_filter :check_user, only: [:edit, :update, :destroy]
def seller
#listings = Listing.where(user: current_user).order("created_at DESC")
end
# GET /listings
# GET /listings.json
def index
if params[:category].blank?
#listings = Listing.all.order("created_at DESC").paginate(:page => params[:page], :per_page => 16)
else
#category_id = Category.find_by(name: params[:category]).id
#listings = Listing.where(category_id: #category_id).order("created_at DESC").paginate(:page => params[:page], :per_page => 16)
end
end
# GET /listings/1
# GET /listings/1.json
def show
end
# GET /listings/new
def new
#listing = Listing.new
end
# GET /listings/1/edit
def edit
end
# POST /listings
# POST /listings.json
def create
#listing = Listing.new(listing_params)
#listing.user_id = current_user.id
if current_user.recipient.blank?
Stripe.api_key = ENV["STRIPE_API_KEY"]
token = params[:stripeToken]
recipient = Stripe::Recipient.create(
:name => current_user.name,
:type => "individual",
:bank_account => token
)
current_user.recipient = recipient.id
current_user.save
end
respond_to do |format|
if #listing.save
format.html { redirect_to #listing, notice: 'Listing was successfully created.' }
format.json { render :show, status: :created, location: #listing }
else
format.html { render :new }
format.json { render json: #listing.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /listings/1
# PATCH/PUT /listings/1.json
def update
respond_to do |format|
if #listing.update(listing_params)
format.html { redirect_to #listing, notice: 'Listing was successfully updated.' }
format.json { render :show, status: :ok, location: #listing }
else
format.html { render :edit }
format.json { render json: #listing.errors, status: :unprocessable_entity }
end
end
end
# DELETE /listings/1
# DELETE /listings/1.json
def destroy
#listing.destroy
respond_to do |format|
format.html { redirect_to listings_url, notice: 'Listing was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_listing
#listing = Listing.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def listing_params
params.require(:listing).permit(:name, :category_id, :description, :price, :image)
end
def check_user
if current_user != #listing.user
redirect_to root_url, alert: "Sorry, this listing belongs to someone else"
end
end
end
my current routes:
Rails.application.routes.draw do
mount RailsAdmin::Engine => '/admin', as: 'rails_admin'
resources :categories
devise_for :users
resources :listings do
resources :orders, only: [:new, :create]
end
get 'pages/about'
get 'pages/contact'
get 'seller' => "listings#seller"
get 'sales' => "orders#sales"
get 'purchases' => "orders#purchases"
# or
root 'listings#index'
end
and finally, my listing model:
class Listing < ActiveRecord::Base
if Rails.env.development?
has_attached_file :image, :styles => { :medium => "200x", :thumb => "100x100>" }, :default_url => "404.jpg"
else
has_attached_file :image, :styles => { :medium => "200x", :thumb => "100x100>" }, :default_url => "404.jpg",
:storage => :dropbox,
:dropbox_credentials => Rails.root.join("config/dropbox.yml"),
:path => ":style/:id_:filename"
end
validates_attachment_content_type :image, :content_type => /\Aimage\/.*\Z/
validates :name, :category_id, :description, :price, presence: true
validates :price, numericality: { greater_than: 0}
validates_attachment_presence :image
belongs_to :user
belongs_to :category
has_many :orders
end
my index page where I want to link to the seller specific page
<div class="center">
<div class="row">
<% #listings.each do |listing| %>
<div class="col-md-3">
<div class="thumbnail">
<%= link_to image_tag(listing.image.url), listing %>
<div class="caption">
<h3><%= listing.name %></h3>
<p><%= number_to_currency(listing.price) %></p>
<p><%= "Sold by #{listing.user.name}" %></p>
</div>
</div>
</div>
<% end %>
</div>
</div>
<br>
<div class="center">
<%= will_paginate #posts, renderer: BootstrapPagination::Rails %>
</div>
<% if user_signed_in? %>
<div class="right">
<%= link_to new_listing_path, class: "btn btn-primary", data: { no_turbolink: true } do %>
<i class="glyphicon glyphicon-plus"></i> New Listing
<% end %>
</div>
<% end %>
<br>
'User' is a model that you have created: devise only manages sessions, registrations, passwords, unlocks, and confirmations (the gem provides a controller for each one of these).
You should create your own UsersController, in which you can define the show action that you need. You should also declare a different path in your routes, or you'd have a conflict as '/users' is already used by devise. Something like
resources :users, only: [:show], path: 'sellers'
Then you can use
<p><%= "Sold by #{link_to listing.user.name, user_path(listing.user)}" %></p>
i get an error
undefined method `photo' for #<Post::ActiveRecord_Relation:0x00000004ad42e8>
my posts.index.html.erb
<%= image_tag #post.photo.url(:small) %>
gives me the above error and if i iterate
<% #post.each do |image| %>
<%= image_tag image.photo.url %>
<% end %>
i get this new error
SQLite3::SQLException: no such column: position: SELECT "posts".* FROM "posts" ORDER BY position ASC
here is my model, post.rb
Class Post < ActiveRecord::Base
require 'digest/md5'
has_attached_file :photo, :styles => { :medium => "300x300>", :thumb => "100x100>" }, :default_url => "/images/:style/missing.png",
:path => ":rails_root/public/assets/images/:id/:style/:basename.:extension"
validates_attachment_content_type :photo, :content_type => /\Aimage\/.*\Z/
validates_attachment_size :photo, :less_than => 5.megabytes
validates_attachment_content_type :photo, :content_type => ['image/jpeg', 'image/png']
include PublicActivity::Model
tracked
end
and my posts_controller.rb
class PostsController < ApplicationController
before_action :authenticate_user!
def index
##hotels = hotels.new()
#activities = PublicActivity::Activity.order("created_at desc")
#post = Post.order('position ASC')
respond_to do |format|
format.html # show.html.erb
format.json { render json: #picture }
end
end
def show
#post = Post.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #picture }
end
end
def new
#post = Post.new
respond_to do |format|
format.html # show.html.erb
format.json { render json: #picture }
end
end
def create
##post = Post.create( user_params )
#post = Post.new(params[:posts].permit(:hotels, :photo, :number, :price, :guest_house, :restaurant,:lodges, :description, :region))
if #post.save
redirect_to(:controller => 'homes',:action=> 'index')
else
render('new')
end
end
def edit
#post = Post.find(params[:id])
end
def update
#post = Post.find(params[:id])
#post = Post.update_attributes()
end
def delete
#post = Post.find(params[:id])
end
#def user_params
#params.require(:post).permit(:photo)
#end
end
i also have the public activity gem installed on my app and when i try to display the photos using
<%= link_to activity.trackable.photo %>
i get a link to where the photo was saved but not the actual image as shown below. help me out
Ah I finally realized my mistake. i used the link_to tag instead of the image_tag
Environment:
Windows 8.1
Rails4
Ruby 2
I am using Devise and I have two separate controllers: users_controller.rb and registrations_controller.rb.
Following is my registrations_controller.rb:
class RegistrationsController < Devise::RegistrationsController
before_filter :update_sanitized_params, if: :devise_controller?
def update_sanitized_params
devise_parameter_sanitizer.for(:sign_up) {|u| u.permit(:first, :last,
:email, :password,
:password_conf, :password_changed_at)}
devise_parameter_sanitizer.for(:account_update) {|u| u.permit(:first, :last, :salutation,
:email, :password,
:password_conf, :password_changed_at, :current_passwor)}
end
# GET /registrations/new
def new
super
end
# POST /registrations
# POST /registrations.json
def create
#user = User.new(registration_params)
#user.email = #user.email.downcase
##user.slug = "#{#user.first.downcase}_#{#user.last.downcase}_#{#user.email}"
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: t('registration_successfully_created') }
format.json { render :show, status: :created, location: #user }
else
format.html { render :new }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# DELETE /registrations/1
# DELETE /registrations/1.json
def destroy
#user.destroy
respond_to do |format|
format.html { redirect_to registrations_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_registration
#user = User.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def registration_params
params[:user]
end
end
and following is my User model: user.rb
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:password_expirable, :confirmable, :lockable, :timeoutable
validates :first, presence: true
validates :last, presence: true
validates :email, :email => true, presence: true, uniqueness: {case_sensitive: false}
before_save { |user| user.email = email.downcase }
end
When I try to create a new user, I get an error message:
ActiveModel::ForbiddenAttributesError
The following line is highlighted in the registrations controller:
#user = User.new(registration_params)
Witht the additional debug information:
{"utf8"=>"✓", "authenticity_token"=>"CRwY4emBZJXhH7kMNGQZR5H1D3D0IJrHCnBzs5PTE8U=", "user"=>{"email"=>"xxxx#jkjjjkj.com", "password"=>"xxxxxxx", "password_confirmation"=>"xxxxxxx", "first"=>"John", "last"=>"Doe"}, "commit"=>"Create User", "action"=>"create", "controller"=>"registrations"}
Any ideas?
You have defined a method for strong parameters but you cannot just return the params hash - instead you have to specifically whitelist the attributes you wish to pass on to the model.
def registration_params
params.require(:user).permit(:email, :password, :password_confirmation, ...) # etc for the rest of your attributes
end
I've done a simple project about paper_trail, however I encountered a problem. When I created or updated completely there were two message show in the view:
Product was successfully created. undo
Product was successfully created. <a data-method="post" href="/versions/148/revert" rel="nofollow">undo</a>
here is my controller file:
class ProductsController < ApplicationController
before_action :set_product, only: [:show, :edit, :update, :destroy]
# GET /products
# GET /products.json
def index
#products = Product.order(:name)
respond_to do |format|
format.html
format.csv { send_data #products.to_csv }
end
end
# GET /products/1
# GET /products/1.json
def show
end
# GET /products/new
def new
#product = Product.new
end
# GET /products/1/edit
def edit
end
# POST /products
# POST /products.json
def create
#product = Product.new(product_params)
respond_to do |format|
if #product.save
format.html { redirect_to #product, notice: "Product was successfully created. #{undo_link}" }
format.json { render action: 'show', status: :created, location: #product }
else
format.html { render action: 'new' }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /products/1
# PATCH/PUT /products/1.json
def update
respond_to do |format|
if #product.update(product_params)
format.html { redirect_to product_url, notice: 'Product was successfully updated.' "#{undo_link}" }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
# DELETE /products/1
# DELETE /products/1.json
def destroy
#product.destroy
respond_to do |format|
format.html { redirect_to products_url, notice: "Successfully destroyed product. #{undo_link}" }
format.json { head :no_content }
end
end
def import
Product.import(params[:file])
redirect_to root_url, notice: "Products imported."
end
private
# Use callbacks to share common setup or constraints between actions.
def set_product
#product = Product.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def product_params
params.require(:product).permit(:name, :price)
end
def undo_link
view_context.link_to("undo", revert_version_path(#product.versions.scoped.last), :method => :post)
end
end
and the layout file here:
<!DOCTYPE html>
<html>
<head>
<title>Store</title>
<%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track" => true %>
<%= javascript_include_tag "application", "data-turbolinks-track" => true %>
<%= csrf_meta_tags %>
</head>
<body>
<div id="container">
<% flash.each do |name, msg|%>
<%= content_tag :div, raw(msg), :id => "flash_#{name}" %>
<% end %>
<%= yield %>
</div>
</body>
</html>
I expect to show message once, however it show twice, so please tell me where my errors?
You are calling a flash message in both your create action and your view.
Create action:
format.html { redirect_to #product, notice: "Product was successfully created. #{undo_link}" }
View:
<% flash.each do |name, msg|%>
<%= content_tag :div, raw(msg), :id => "flash_#{name}" %>
<% end %>
The first gives:
Product was successfully created. undo
The latter show all raw output because of raw(msg):
Product was successfully created. <a data-method="post" href="/versions/148/revert" rel="nofollow">undo</a>