Paperclip and carrierwave - file does not save + other issues - ruby-on-rails

I have few issues about rails app I've made:
1. I've tried to use paperclip and carrierwave, but none of them save the file I want to attach to a specified folder. Attachment should be joined to user model:
class UsersController < ApplicationController
def new
#users = User.new
end
def create
#user = User.new(user_params)
if #user.save
session[:user_id] = #user.id
redirect_to '/'
else
redirect_to '/signup'
end
end
private
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :PESEL, :phone, :cv, :password)
end
end
user controller:
class UsersController < ApplicationController
def new
#users = User.new
end
def create
#user = User.new(user_params)
if #user.save
session[:user_id] = #user.id
redirect_to '/'
else
redirect_to '/signup'
end
end
private
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :PESEL, :phone, :cv, :password)
end
end
paperclip:
class AddAttachmentCvToUsers < ActiveRecord::Migration
def self.up
change_table :users do |t|
t.attachment :cv
end
end
def self.down
remove_attachment :users, :cv
end
end
What is the task - I want to have users 'joined' with the attachment, and then joined with jobapps model - so it will create new job app id, where the empoyee can decide if it is accepted or not. And I have a trouble with attaching a CV file.

Related

Save form data(text field) in database in rails

I have created a user controller with login and logout.
After login user should be able to give some comment in text box input and it should be saved in db.
How to associate the comment to the user. My users controller is
class UsersController < ApplicationController
def new
end
def create
user = User.new(user_params)
if user.save
session[:user_id] = user.id
redirect_to '/url'
else
redirect_to '/signup'
end
end
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
end
my urls controller is
class UrlsController < ApplicationController
def new
end
def create
url = Url.new(url_params)
url.save
redirect_to #url
end
def url_params
params.require(:url).permit(:url)
end
end
I am getting error in url_params. How it should be for a text field?
For example you need to create Comment model
class Comment < ApplicationRecord
belongs_to :user
end
class User < ApplicationRecord
has_many :comments
end
and create CommentsController
class CommentsController < ApplicationController
before_action :set_user
def create
#user.comments.create(comment_params)
redirect_to root_url
end
private
def set_user
#user = User.find(session[:user_id])
end
def comment_params
params.require(:comment).permit(:text)
end
end

Ruby on Rails - pundit gem - undefined method

Don't know why this is happening here.
NoMethodError in PostsController#update
undefined method `user' for nil:NilClass
My user has admin : true and I can't update other users.posts.
I want to let all users see the content, but only registered users can create content. And if the user is admin or the creator of that content he can edit/update/destroy it as well.
post.rb
class Post < ApplicationRecord
belongs_to :user
has_many :comments, dependent: :destroy
validates :title, presence: true, length: { minimum: 5 }
validates :body, presence: true, length: { minimum: 240 }
end
user.rb
class User < ApplicationRecord
include Encryptable
has_many :posts, dependent: :destroy
has_many :comments, dependent: :destroy
has_attached_file :avatar
validates_attachment_content_type :avatar, content_type: /\Aimage\/.*\z/
validates :level, numericality: { less_than_or_equal_to: 100, only_integer: true }, allow_blank: true
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable
before_validation :downcase_email #, :populate_iv_fields #if you need/want iv to change more often
before_create :create_encryption_key
after_create :save_encryption_key
after_create :build_user_consents
attr_encrypted :email, key: :encryption_key
has_many :user_consents, dependent: :destroy
#entry point for exporting user's personal information
def self.export_personal_information(user_id)
return nil unless User.exists?(user_id)
descendants = ApplicationRecord.descendants.reject{|model| !model.has_personal_information?}
result = Hash.new
descendants.each do |descendant|
result[descendant.name] = descendant.export_personal_information_from_model(user_id)
end
return result
end
#simplest example, we just export to json
def self.export_personal_information_from_model(user_id)
return User.find(user_id).to_json
end
#overwrite this to true for methods that you will want to be included in export_personal_information
def self.has_personal_information?
true
end
#helper method if you are creating a user from console and want them to have all consents set
def fill_consents
hash = Hash.new
ConsentCategory.all.map(&:id).each do |id|
hash[id]='on'
end
self.registration_consents=hash
end
#unfortunately not having an email field that you can just "write to" breaks
#Devise. Below some necessary workarounds
def email_changed?
encrypted_email_changed?
end
def downcase_email
self.email = self.email.downcase
end
def registration_consents=(consents)
#consents = consents
end
def registration_consents
#consents
end
validate :validate_consents_completeness
validates_presence_of :email, if: :email_required?
validates_uniqueness_of :username, allow_blank: false, if: :username_changed?
validates_length_of :username, within: 6..20, allow_blank: true
validate :validate_email_uniqueness #validates_uniqueness_of :email, allow_blank: true, if: :email_changed?
validates_format_of :email, with: Devise.email_regexp, allow_blank: true, if: :email_changed?
validates_presence_of :password, if: :password_required?
validates_confirmation_of :password, if: :password_required?
validates_length_of :password, within: Devise.password_length, allow_blank: true
def password_required?
!persisted? || !password.nil? || !password_confirmation.nil?
end
#end original devise
def email_changed?
self.encrypted_email_changed?
end
def email_required?
true
end
def email_unique?
records = Array(self.class.find_by_email(self.email))
records.reject{|u| self.persisted? && u.id == self.id}.empty?
end
#unfortunately, this is an O(n) operation now that has to go through ALL the users to see if an email is unique. Sorry!
#if you need it to ne O(1) then consider adding email_hash field instead
def self.find_by_email(email)
users = User.all
users.each do |user|
return user if user.email.downcase == email.downcase
end
return nil
end
protected
def validate_email_uniqueness
errors.add(:email, :taken) unless email_unique?
end
def validate_consents_completeness
return if self.id #we assume that already created user has all consents
errors.add(:registration_consents, 'Sie müssen allen erforderlichen Bedingungen zustimmen um fortzufahren.') and return unless self.registration_consents
consents = ConsentCategory.where(mandatory: true).map(&:id)
ids = self.registration_consents.keys.map(&:to_i) #we are relying on a fact that checkboxes that are not checked are not sent to Rails back-end at all
consents.each do |consent_type|
errors.add(:registration_consents, 'Sie müssen allen erforderlichen Bedingungen zustimmen um fortzufahren.') and return unless ids.include?(consent_type)
end
end
def build_user_consents
ids = registration_consents.keys
categories = ConsentCategory.where(id: ids)
raise 'Die vom Benutzer eingereichte Zustimmungsliste enthält Objekte, die nicht in der Datenbank vorhanden sind!' if categories.count != ids.count
categories.each do |category|
consent = UserConsent.new
consent.consent_category = category
consent.user = self
consent.requires_revalidation = false
consent.agreed_at = self.created_at
consent.save!
end
end
end
post_policy.rb
class PostPolicy < ApplicationPolicy
attr_reader :user, :post
def initialize(user, post)
#user = user
#post = post
end
def index?
true
end
def create?
user.present?
end
def new?
user.present?
end
def update?
return true if post.user_id == user.id || user == user.admin?
end
def destroy?
return true if post.user_id == user.id || user == user.admin?
end
private
def post
record
end
end
application_policy.rb
class ApplicationPolicy
attr_reader :user, :record
def initialize(user, record)
#user = user
#record = record
end
def index?
false
end
def show?
false
end
def create?
false
end
def new?
create?
end
def update?
user.admin?
end
def edit?
user.admin?
end
def destroy?
user.admin?
end
class Scope
attr_reader :user, :scope
def initialize(user, scope)
#user = user
#scope = scope
end
def resolve
scope.all
end
end
end
post_controller
class PostsController < ApplicationController
before_action :find_post, only: %i[destroy edit update comment_owner upvote downvote]
after_action :verify_authorized, except: [:index, :show]
layout '_app_nav'
def index
return redirect_to post_path(params[:post_id]) if params[:post_id]
return redirect_to user_path(params[:user_id]) if params[:user_id]
#post = Post.all.order('created_at DESC')
#posts = Post.all.order('created_at DESC')
#user = User.all
#posts = if params[:suche]
else
Post.all.order('created_at DESC')
end
#comments = Comment.all
end
def new
#post = Post.new
end
def create
#post = current_user.posts.build(post_params)
authorize #post
if #post.save!
redirect_to #post
else
render 'new'
end
end
def show
#post = Post.find(params[:id])
#user = #post.user
#comments = Comment.where(post_id: #post).order('created_at DESC').paginate(:page => params[:page], :per_page => 5)
end
def edit
authorize #post
#post = Post.find(params[:id])
end
def update
#user = User.find(params[:id])
#post = Post.find(params[:id])
authorize #post
#post.update(title: params[:title], body: params[:post_params])
redirect_to post_path(#post)
end
def destroy
#post = Post.find(params[:id])
#post.destroy
authorize #post
redirect_to posts_path
end
=begin
def upvote
#post.upvote_from current_user
redirect_to post_path(#post)
end
def downvote
#post.downvote_from current_user
redirect_to post_path(#post)
end
=end
private
def post_params
params.require(:post).permit(:title, :body, :user_id)
end
def find_post
#post = Post.find(params[:id])
end
end
application_controller
class ApplicationController < ActionController::Base
include Pundit
protect_from_forgery with: :exception
before_action :authenticate_user!
before_action :configure_permitted_parameters, if: :devise_controller?
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up) do |user_params|
user_params.permit(:username, :email, :password, :password_confirmation, registration_consents: {})
end
end
private
def user_not_authorized
flash[:alert] = 'test'
redirect_to(root_path)
end
end
registrations_controller:
class RegistrationsController < Devise::RegistrationsController
private
def account_update_params
params.require(:user).permit(:email, :username, :avatar, :current_password, :password, :password_confirmation)
end
end
edit:
updating my post_policy.rb with #post such as return true if user.present? && user == #post.user || user == user.admin? resolves in -> Pundit::NotAuthorizedError in PostsController#update
not allowed to update?
In your PostsController, you need to include update method inside array where you specify before which methods should authenticate_user before action run:
before_action :authenticate_user!, only: [:create, :destroy, :new, :edit, :update]
If you're using devise you can use this callback, in your application_controller.rb to validate you have a user logged in.
before_action :authenticate_user!
With that you avoid doing
user.present?
Your post_policy.rb should look like this
class PostPolicy < ApplicationPolicy
attr_reader :user, :post
def initialize(user, post)
#user = user
#post = post
end
def index?
true
end
def create?
user.present?
end
def new?
user.present?
end
def update?
return true if record.user_id == user.id || user == user.admin?
end
def destroy?
return true if record.user_id == user.id || user == user.admin?
end
private
def post
record
end
end
Also, to avoid that users can enter the links in the browser, you can do an extra step on you controller, which is adding the following callback and method
class PostsController < ApplicationControl
before_action :authorization
private
def authorization
authorize(Post)
end
end
EDIT:
Make sure your ApplicationController looks like this one to prevent the error Pundit::NotAuthorizedError.
class ApplicationController < ActionController::Base
include Pundit
before_action :authenticate_user!
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
private
def user_not_authorized
flash[:alert] = 'You are not authorized to perform this action.'
redirect_to(root_path)
end
end

undefined method `build_profile' for #<User:0x000000035b9ae8>

I can't figure out the problem with my code. I'm trying to add a profile to my user. For this I get my user ID and attach this to my profile in a DB. However after submitting the form it gives the following error: NoMethodError in ProfilesController#create
class ProfilesController < ApplicationController
# GET to /users/:user_id/profile/new
def new
#profile = Profile.new
end
# POST to /users/:user_id/profile
def create
# Ensure that we have the user who is filling out form
#user = User.find(params[:user_id])
# Create profile linked to this specific user
#profile = #user.build_profile( profile_params )
if #profile.save
flash[:success] = "Profile updated!"
redirect_to root_path
else
render action: :new
end
end
private
def profile_params
params.require(:profile).permit(:first_name, :last_name, :phone_number, :contact_email, :banking)
end
end
Your models need to be some thing like this... I assume you are missing a has_many or belongs_to in the user modal.
class User
has_many :profile
# or belongs_to :profile
end
class Profile
belongs_to :user
# or has_many :users
end
Give your modals if it doesn't work, we can fix it up.
try to replace
#user = User.find(params[:user_id])
#profile = #user.build_profile( profile_params )
by
#profile.user_id = current_user.id
for user_id it depend how you named your user id foreign key
You may do
def create
#profile = Profile.new(profile_params)
if #profile.save
flash[:success] = "Profile updated!"
redirect_to root_path
else
render action: :new
end
end
private
def profile_params
params.require(:profile).permit(:first_name, :last_name, :phone_number, :contact_email, :banking, :user_id)
end
Or
def profile_params
params.require(:profile).permit(:first_name, :last_name, :phone_number, :contact_email, :banking).merge!(user: current_user)
end
Regarding the error "NoMethodError in ProfilesController#create" it may happen because it is not declared in the routes.rb or it does a HTTP Get instead of a Post.
in the routes.rb file,
resources :users do
resources :profiles
end
http://guides.rubyonrails.org/routing.html#nested-resources

Setting an id as a default foreign key in rails

I am having challenges assigning a current user a role in a team the user is creating. I want to assign the user that creates the team the role of the captain which could be changed later.
I'm currently using the create_asociation method that comes with has_one relationship, as this instantiates the values of the associated model, which i want to be instantiated with the current user but get the error Can't mass assign protected attribute: captain. Captain is a self join model with user as i will like to use captain.teammates and team.captain.
Below are the models involved.
User and Captain Model
class User < ActiveRecord::Base
has_one :profile
has_many :teammates, :class_name => "User", :foreign_key => "captain_id"
belongs_to :captain, :class_name => "User"
belongs_to :team
# before_create :build_profile
after_create :build_default_profile
accepts_nested_attributes_for :profile
attr_accessible :email, :password, :password_confirmation, :profile_attributes, :captain_id
def build_default_profile
Profile.create(user_id: self.id)
end
has_secure_password
before_save { email.downcase! }
before_save :create_remember_token
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, presence: true, length: { minimum: 6 }
validates :password_confirmation, presence: true
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
end
Team Model
class Team < ActiveRecord::Base
has_many :profiles, through: :users
has_one :captain, :class_name => "User", foreign_key: :captain_id
has_one :result, as: :result_table
attr_accessible :teamname, :color, :result_attributes, :captain_attributes
after_create :build_result_table
after_create :build_default_captain
accepts_nested_attributes_for :profiles
accepts_nested_attributes_for :captain
accepts_nested_attributes_for :result
def build_result_table
Result.create(result_table_id: self.id, result_table_type: self.class.name)
end
def build_default_captain
# Team.captain = User
# Captain.create(team_id: self.id, captain_id: user.id)
end
end
User Controller
class UsersController < ApplicationController
before_filter :signed_in_user, only: [:index, :edit, :update, :destroy]
before_filter :correct_user, only: [:edit, :update]
before_filter :admin_user, only: :destroy
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save!
sign_in #user
flash[:success] = "Welcome to the JHDC Mini Olympics Web Application; Thanks for singing Up"
redirect_to user_profile_path(#user, #profile)
else
flash[:error_messages]
render 'new'
end
end
def show
#user = User.find(params[:id])
end
def index
#users = User.paginate(page: params[:page])
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"
redirect_to user_profile_path(#user, #profile)
else
render 'edit'
end
end
def destroy
User.find(params[:id]).destroy
flash[:success] = "User deleted."
redirect_to users_url
end
private
def signed_in_user
unless signed_in?
store_location
redirect_to signin_url, notice: "Please sign in."
end
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
def user_params
params.require(:user).permit(:email, :password, :password_confirmation)
end
end
end
Team Controller
class TeamsController < ApplicationController
def new
#team = Team.new
end
def create
#team = Team.new(params[:team])
#captain = #team.create_captain(captain: current_user)
if current_user.admin?
if #team.save!
flash[:success] = "Team created."
redirect_to #team
else
flash[:error_messages]
render 'new'
end
else
flash[:error] = "Sorry, you don't have the authority to create a Team"
redirect_to current_user
end
end
def index
#teams = Team.paginate(page: params[:page])
end
def show
#team = Team.find(params[:id])
end
def edit
if current_user.admin?
#team = Team.find(params[:id])
else
flash[:error] = "Sorry you dont have the authourity to edit a Team"
redirect_to current_user
end
end
def update
#team = Team.find(params[:id])
if #team.update_attributes(params[:team])
flash[:success] = "Team Updated"
redirect_to #team
else
render 'edit'
end
end
def destroy
Team.find(params[:id]).destroy
flash[:success] = "Team is deleted."
redirect_to teams_url
end
private
def team_params
params.require(:team).permit(:teamname, :color)
end
end
The admin is currently a way i'm using to restrict the user that can create a team but i plan to use gems like declarative authorization to create role based authorization. Thanks
The error you are getting is because the attribute :captain is not declared as attr_accessible
Either set the attribute :captain in your list of attr_accessible for the User model, or change the code form
Captain.create(team_id: self.id, captain_id: user.id)
to
captain = Captain.new
captain.team_id = self.id
captain.captain_id = user.id
captain.create
in this way, the attribute won't be set by mass-assignment and won't raise the error
Edited
After checking your code twice, just realized that you don't have a Captain model, actually :captain is a relation for the user and a relation from the Team to the User.
So on Team model, take off the build_default_captain stuff and the after_create :build_default_captain, I would say to replace with something like
after_save :set_default_captain
def set_default_captain
if captain_id_changed?
profiles.each do |user|
user.captain = captain
user.save
end
end
end
so every time the captain_id change for the model, you change the captain_id of all its profiles (users)
Then on the Team controller, on the action create, instead of
#team = Team.new(params[:team])
#captain = #team.create_captain(captain: current_user)
do something like
#team = Team.new(params[:team])
#team.captain = current_user
if current_user.admin?
if #team.save!
current_user.update_attribute(:team_id, #team.id)
flash[:success] = "Team created."
redirect_to #team
else
flash[:error_messages]
render 'new'
end
else
flash[:error] = "Sorry, you don't have the authority to create a Team"
redirect_to current_user
end
so on the last part of the code, you set the captain of the team to the current user and set the user team to the current team once its saved, you can also improve the code with current_user.build_team to avoid saving current_user.update_attribute

Default boolean value not being set Rails 4 Postgres

I have created a migration to my users table with the following code:
add_column :users, :email_confirmed, :boolean, :default => false
however when a new user is created the :email_confirmed field is automatically set to true. Has this happened to anyone? Am I missing something simple? Any insights are welcome.
My User model:
class User < ActiveRecord::Base
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
has_secure_password
before_save { email.downcase! }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-]+(?:\.[a-z\d\-]+)*\.[a-z]+\z/i
before_create :create_remember_token
before_create :confirmation_token
validates :name, presence: true, length: { maximum: 50 }
validates :email, presence: true,
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
validates :password, length: { minimum: 6 }, :unless => :email_activate
def feed
Micropost.from_users_followed_by(self)
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
def User.new_remember_token
SecureRandom.urlsafe_base64
end
def User.digest(token)
Digest::SHA1.hexdigest(token.to_s)
end
def email_activate
self.email_confirmed = true
save!(:validate => false)
end
def send_password_reset
self.password_reset_token = SecureRandom.urlsafe_base64.to_s
self.password_reset_sent_at = Time.zone.now
save!(:validate => false)
UserMailer.password_reset(self).deliver
end
private
def create_remember_token
self.remember_token = User.digest(User.new_remember_token)
end
def confirmation_token
# only generate if you did not manually set value
if self.confirm_token.blank?
self.confirm_token = SecureRandom.urlsafe_base64.to_s
end
end
end
and my Users Controller:
class UsersController < ApplicationController
before_action :signed_in_user, only: [:index, :edit, :update, :destroy, :following, :followers]
before_action :correct_user, only: [:edit, :update]
before_action :admin_user, only: :destroy
before_action :registered_already, only: [:new, :create]
def index
#users = User.paginate(page: params[:page])
end
def show
#user = User.find(params[:id])
#microposts = #user.microposts.paginate(page: params[:page])
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
UserMailer.registration_confirmation(#user).deliver
flash[:success] = "Please confirm your email address to continue"
redirect_to root_url
else
flash[:error] = "Ooooppss, something went wrong!"
render 'new'
end
end
def edit
end
def update
if #user.update_attributes(user_params)
flash[:success] = "Profile updated"
redirect_to #user
else
render 'edit'
end
end
def destroy
user = User.find(params[:id])
unless current_user?(user)
user.destroy
flash[:success] = "User deleted."
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
def confirm_email
user = User.find_by_confirm_token(params[:id])
if user
user.email_activate
flash[:success] = "Welcome to the Sample App!"
redirect_to root_url
else
flash[:error] = "Sorry. User does not exist"
redirect_to root_url
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
# Before filters
def correct_user
#user = User.find(params[:id])
redirect_to(root_url) unless current_user?(#user)
end
def admin_user
redirect_to(root_url) unless current_user.admin?
end
def registered_already
redirect_to root_url, notice: "You are already registered." if signed_in?
end
end
my Sessions Controller
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by_email(params[:email].downcase)
if user && user.authenticate(params[:password])
if user.email_confirmed
sign_in user
redirect_back_or user
else
flash.now[:error] = 'Please activate your account by following the
instructions in the account confirmation email you receieved to proceed'
end
else
flash.now[:error] = 'Invalid email/password combination' # Not quite right!
render 'new'
end
end
def destroy
sign_out
redirect_to root_url
end
end
I have a feeling that the email_activate method in the users model is being called on the create action but I don't know why?....
Just while I was doing this I commented out the `:unless => :email_activate' in the password validator. Now everything works. I am surprised that this was the reason as it does not make logical sense to my (admittedly somewhat limited) understanding of rails. Could someone explain why this was setting the email confirmed field to true please?
If you want the default value to always be set, you can't allow null values. Specify :null => false
add_column :users, :email_confirmed, :boolean, :null => false, :default => false

Resources