I want to concatenate two fiels (address and place) into 1 field (location).
I have created the following code in my pins controller:
class PinsController < ApplicationController
before_action :set_pin, only: [:show, :edit, :update, :destroy, :like, :unlike]
before_action :authenticate_user!, except: [:index, :show]
before_action :correct_user, only: [:destroy]
before_save :set_location
def set_location
location = "#{address} #{place}"
end
...
private
# Use callbacks to share common setup or constraints between actions.
def set_pin
#pin = Pin.find(params[:id])
end
def correct_user
#pin = current_user.pins.find_by(id: params[:id])
redirect_to pins_path, notice: "It is only allowed to change the restaurants you have added my yourself." if #pin.nil?
end
# Never trust parameters from the scary internet, only allow the white list through.
def pin_params
params.require(:pin).permit(:description, :image, :name, :address, :place, :postal_code, :telephone_number, :website, :emailadress, :location)
end
end
I get this error message
undefined method `before_save' for PinsController:Class
Does anyone knows what I am doing wrong?
before_save is callback for Models, not for Controllers.
You should do:
class Pin < ActiveRecord::Base
before_save :set_location
def set_location
self.location = "#{self.address} #{self.place}"
end
end
You are using the before_save hook in your controller instead of the model.
Move this code to your model and it should work.
class Pin < ActiveRecord::Base
before_save :set_location
# ...
def set_location
self.location = "#{address} #{place}"
end
end
Related
I created a userstamps method to know which user created and edited a data. I have this table Illustrator that I am trying to assign created_by to the current_user id. But when it saves, created_by is nil and don't show any error. When I put raise right before illustrator.save, the #illustrator.created_by is exactly the current_user.id but when I check the value in db, is nil.
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable,
:custom_authenticatable
belongs_to :account
belongs_to :role
cattr_accessor :current_user
validates :email, presence: true, uniqueness: true
validates :email, format: { with: URI::MailTo::EMAIL_REGEXP }
validates :password,
length: { minimum: 6 },
if: -> { new_record? || !password.nil? }
enum gen: { masculino: 1, feminino: 2 }
private
#apenas usuário com role de admim pode logar.
def valid_for_custom_authentication?(password)
#self.role.name == 'admin'
self.role_id === 2
end
end
class ApplicationController < ActionController::Base
before_action :authenticate_user!
helper_method :current_user
private
def current_user=(user)
#current_user = user
end
end
class IllustratorsController < ApplicationController
before_action :authenticate_user!
def new
#illustrator = Illustrator.new
end
def create
#illustrator = Illustrator.new(illustrator_params)
#illustrator.created_by = current_user.id
if #illustrator.save
redirect_to illustrator_path(#illustrator), notice: 'O autor foi criado com sucesso.'
else
render :new
end
end
private
def illustrator_params
params.require(:illustrator).permit(:name, :display_name, :email, :phone, :status, :notes, :created_by)
end
end
Rails.application.routes.draw do
get 'payments/index'
devise_for :users
root to: 'pages#home'
resources :books
resources :authors
resources :publishers
resources :illustrators
resources :plans do
resources :accounts, only: %i[new create] do
end
end
resources :payments, only: %i[index]
resources :accounts, only: %i[index show edit update destroy] do
resources :users, only: %i[new create] do
resources :roles
end
end
resources :users, only: %i[edit update index show destroy]
#API routes
namespace :api do
namespace :v1 do
get 'default/:id', to: 'plans#change_plans'
get 'plans', to: 'plans#index'
get 'plans/id', to: 'plans#show'
get 'accounts', to: 'accounts#return'
post 'users', to: 'users#create'
#resources :users
post '/auth/login', to: 'authentication#login'
get '/*a', to: 'application#not_found'
post 'password/forgot', to: 'users#forgot_password'
end
end
end
If you are using devise, you dont need this part:
helper_method :current_user
private
def current_user=(user)
#current_user = user
end
Where did you even find it? Remove it from your codebase!
With devise you don't need any getter or setter methods.
It can possibly be the reason it's not working for you.
If in application_controller you have the before_action :authenticate_user!, current_user method should work right out of the box!
As well you don't need to add the before_action :authenticate_user! again here
class IllustratorsController < ApplicationController
before_action :authenticate_user!
, because you already made it application-wide in application_controller.
Your create method is good. Try removing the abundancies and it should all work.
You have just setter method in your controller where you are setting current_user
def current_user=(user)
#current_user = user
end
You need to add getter method as well like following so that you can use it in your controller
def current_user
#current_user
end
In ruby there is short cut for this attr_accessor :current_user Ref this
I installed devise in a rails app. If a user is log in he could access to every other users edit pages.
For example, i'm user_id 2, i can edit profile of user 1/3/4/5.....when i modify params manually in the route.
Here my App Controller :
class ApplicationController < ActionController::Base
protect_from_forgery
before_action :authenticate_user!
before_action :configure_permitted_parameters, if: :devise_controller?
def configure_permitted_parameters
# For additional fields in app/views/devise/registrations/new.html.erb
devise_parameter_sanitizer.permit(:sign_up, keys: [:first_name, :last_name, :company, :position, :office_phone, :mobile_phone, :address, :description, :radius, :photo_company_logo, :photo_presentation, photos_projet_1: [], photos_projet_2: [], photos_projet_3: [], photos_projet_4: []])
# For additional in app/views/devise/registrations/edit.html.erb
devise_parameter_sanitizer.permit(:account_update, keys: [:first_name, :last_name, :company, :position, :office_phone, :mobile_phone, :address, :description, :radius, :photo_company_logo, :photo_presentation, photos_projet_1: [], photos_projet_2: [], photos_projet_3: [], photos_projet_4: []])
end
end
Here my User Controller :
class UsersController < ApplicationController
skip_before_action :authenticate_user!, only: [:index, :show]
before_action :set_user, only: [:show, :edit, :update]
def index
#client = Client.new
#users = User.all
#users = User.where.not(latitude: nil, longitude: nil)
#hash = Gmaps4rails.build_markers(#users) do |user, marker|
marker.lat user.latitude
marker.lng user.longitude
end
end
def show
#client = Client.new
#user = User.find(params[:id])
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
#user.save
redirect_to users_path
end
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
#user.update(user_params)
redirect_to user_path(#user)
end
private
def user_params
params.require(:user).permit(:company, :first_name, :last_name, :position, :mobile_phone, :office_phone, :email, :address, :description, :radius, :nettoyage_toiture, :photo_company_logo, :photo_presentation, photos_projet_1: [], photos_projet_2: [], photos_projet_3: [], photos_projet_4: [])
end
def set_user
#user = User.find(params[:id])
end
end
Here mu User model :
class User < ApplicationRecord
has_attachment :photo_presentation
has_attachment :photo_company_logo
has_many :projects, dependent: :nullify
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
#geocoder for google maps
geocoded_by :address
after_validation :geocode, if: :address_changed?
end
Here my routes :
Rails.application.routes.draw do
ActiveAdmin.routes(self)
devise_for :users
root to: 'pages#home'
resources :users do
resources :projects
end
resources :clients, only: [:new, :create, :show]
mount Attachinary::Engine => "/attachinary"
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
Thanks a lot!
Devise is an authentication library. You have authorization problem. So, you should use something for the authorization. I use CanCan. With it, you can define privileges like this:
can :edit, User, id: current_user.id
If you don't want to learn another library, you can always do ghetto-authorization in your controllers.
class UsersController
before_action :can_edit_only_self, only: [:edit, :update, :destroy]
private
def can_edit_only_self
redirect_to root_path unless params[:id] == current_user.id
end
end
* authentication - I know who you are
* authorization - I know what you are allowed to do
The problem is this:
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
#user.update(user_params)
redirect_to user_path(#user)
end
If you don't want to users to be able to edit other users then you don't need these 2 methods. You can also change your route file to:
resources :users, except: [:edit, :update] do
resources :projects
end
Update
If you make the previous edits and type rake routes in the terminal, you should see that Devise provides a controller action for editing users. It should be users/edit without the :id param. In the Devise::RegistrationsController, the edit method should just use the current_user helper method for editing the currently logged in user's account information.
If you do want admin user's to be able to edit other users then you'll want to read about one of the following Gems
Can Can
Pundit
With these gems you can define which user "roles" are allowed to edit other users based on their roles. You can also use these gems to give permission to create, read, update, delete other resources.
I have controller looks like
class BarsController < ApplicationController
after_action :some_method, only: [:index]
def index
get_cache = $redis.get('some_key')
if get_cache.present?
# i want to skip after_action callback in here
else
# other stuff
end
end
end
How can I skip after_action :some_method if get_cache is present? I know I can do this with conditional like this
class BarsController < ApplicationController
after_action :some_method, only: [:index], unless: :check_redis
def index
get_cache = $redis.get('some_key')
if get_cache.present?
# i want to skip after_action callback in here
else
# other stuff
end
end
private
def check_redis
$redis.get('some_key')
end
end
But I think that is redundant, because should multiple get to redis.
This should work:
class BarsController < ApplicationController
after_action :some_method, only: [:index], unless: :skip_action?
def index
get_cache = $redis.get('some_key')
if get_cache.present?
#skip_action = true
# i want to skip after_action callback in here
else
# other stuff
end
end
private
def skip_action?
#skip_action
end
end
You can also use attr_accessor :skip_action instead of private method because controller is just object.
This has been asked on SO a lot before, but I can't find anything that quite applies. What I'm trying to do is render an edit form for SettingsController in the edit view of UsersController. I'm super new to RoR, so I'm not even sure what I'm doing wrong.
This questions seems closest, but when I initialize #setting = Setting.new in the Users controller, I get a Settings form without the defaults set for new users in the migration. But if I initialize #setting = Setting.edit or Setting.update, I get an undefined method or wrong number of arguments error.
When the Setting.new form is saved, it throws this error:
undefined method for find_by_id in the SettingsController: app/controllers/settings_controller.rb:43:in `correct_user'.
When I check the database, the settings records are being correctly created when a user is created, but the settings record is not updated when the form is saved.
setting.rb:
class Setting < ActiveRecord::Base
belongs_to :user
validates :user_id, presence: true
end
user.rb:
class User < ActiveRecord::Base
has_many :posts, dependent: :destroy
has_one :setting, dependent: :destroy
after_create :create_setting
end
UsersController:
class UsersController < ApplicationController
before_action :logged_in_user, only: [:edit, :update, :index, :destroy]
before_action :correct_user, only: [:edit, :update]
before_action :admin_user, only: :destroy
def new
#user = User.new
end
def edit
#user = User.find(params[:id])
#setting = Setting.update
end
def update
#user = User.find(params[:id])
#setting = Setting.update
if #user.update_attributes(user_params)
flash[:success] = "Profile updated!"
redirect_to #user
else
render 'edit'
end
end
def settings
#title = "Settings"
#setting = Setting.find_by_user_id(params[:user_id])
end
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
# Confirms the correct user.
def correct_user
#user = User.find(params[:id])
redirect_to(root_url) unless current_user?(#user)
end
end
the SettingsController:
class SettingsController < ApplicationController
before_action :logged_in_user, only: [:create, :edit, :update, :show, :index]
before_action :correct_user, only: [:create, :edit, :update, :show, :index]
def index
#settings = Setting
end
def show
#setting = User.find(params[:id]).setting
end
def new
#setting = Setting.new
end
def edit
#setting = Setting.find(params[:id])
end
def create
#setting = current_user.settings.build(setting_params)
#setting.save
end
def update
#setting = Setting.find(params[:id])
if #setting.update_attributes(post_params)
flash[:success] = "Settings updated!"
redirect_to request.referrer
else
render 'edit'
end
end
private
def setting_params
params.require(:setting).permit(:reading_theme)
end
def correct_user
#setting = current_user.setting.find_by_id(params[:id]) ##the line which throws an error when the form is saved
redirect_to root_url if #setting.nil?
end
end
The form partial:
<%= form_for(#setting) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= radio_button_tag(:reading_theme, "flatly") %>
<%= label_tag(:reading_theme_flatly, "Light (Default)") %>
</div>
<div class="field">
<%= radio_button_tag(:reading_theme, "darkly") %>
<%= label_tag(:reading_theme_darkly, "Dark") %>
</div>
<%= f.submit yield(:button_text), class: "btn btn-primary" %>
<% end %>
routes.rb:
resources :users do
member do
get :following, :followers
end
end
resources :settings, only: [:new, :create, :edit, :update]
...
ETA: the settings migration:
class CreateSettings < ActiveRecord::Migration
def change
create_table :settings do |t|
t.string :reading_theme, default: => "flatly"
t.references :user, index: true, foreign_key: true
t.timestamps null: false
end
end
end
How do I get the proper defaults so that my form can be saved correctly?
Any defaults that you include for fields in the migration will be "unknown" to the model class (Setting) in Ruby. Ruby (or rather Rails ActiveRecord) does not read the default values from the table definition when creating a model object. This can lead to a dual personality problem like you're seeing here.
What you have to do is to add the relevant defaults into the Ruby code, where appropriate. For example, in your Settings controller, you can make these changes:
def new
#setting = Setting.new
# Set any defaults that will be visible to the user on the form
#setting.reading_theme = "flatly"
# The form will allow the user to choose their own values, based on the defaults
end
def create
#setting = current_user.settings.build(setting_params)
# Set any defaults that will NOT be visible to the user
#setting.save
end
This gives you the ability to distinguish between default values that are visible to the user and defaults that are not.
Note that you also have the option of establishing defaults when you create the model object, but this may be more complicated in some situations, and seems to be far less common in practical use. There's an SO answer for that in How to initialize an ActiveRecord with values in Rails?, in case this better suits your needs.
Not can use find_by_id in has_one relationship
#setting = current_user.setting.find_by_id(params[:id])
Just #setting = current_user.setting
I'm following along with One Month Rails and I got stuck at the Pins Users and Associations video. I just can't figure out what's wrong with my code, any help would be appreciated.
When I try to access a pin that I'm not the user of, instead of an alert and redirect coming up I get:
NoMethodError in PinsController#edit
undefined method `pins' for nil:NilClass
Error message says something is wrong in this line:
def correct_user
#pin = current_user.pins.find_by(id: params[:id])
redirect_to pins_path, notice: "Not authorized to edit this pin" if #pin.nil?
end
I tried restarting the whole thing but I hit the same error.
Here is my pins_controller code:
class PinsController < ApplicationController
before_action :set_pin, only: [:show, :edit, :update, :destroy]
before_action :correct_user, only: [:edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
def index
#pins = Pin.all
end
def show
end
def new
#pin = current_user.pins.build
end
def edit
end
def create
#pin = current_user.pins.build(pin_params)
if #pin.save
redirect_to #pin, notice: 'Pin was successfully created.'
else
render action: 'new'
end
end
def update
if #pin.update(pin_params)
redirect_to #pin, notice: 'Pin was successfully updated.'
else
render action: 'edit'
end
end
def destroy
#pin.destroy
redirect_to pins_url
end
private
# Use callbacks to share common setup or constraints between actions.
def set_pin
#pin = Pin.find(params[:id])
end
def correct_user
#pin = current_user.pins.find_by(id: params[:id])
redirect_to pins_path, notice: "Not authorized to edit this pin" if #pin.nil?
end
# Never trust parameters from the scary internet, only allow the white list through.
def pin_params
params.require(:pin).permit(:description)
end
end
Here is my user.rb model code:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :pins
end
Here is my pin.rb model code:
class Pin < ActiveRecord::Base
belongs_to :user
end
And here is the github repo:
https://github.com/ModernMeat/pinteresting
I would suggest you to change order of before_filter's like this
class PinsController < ApplicationController
before_action :authenticate_user!, except: [:index, :show]
before_action :set_pin, only: [:show, :edit, :update, :destroy]
before_action :correct_user, only: [:edit, :update, :destroy]
because you should first authenticate user with devise and only after that check whether it is correct user.
Look at the error message a bit more closely : "for nil:NilClass". This tells you that current_user is nil -- which it is indeed, when the user is not logged in.
If you want to make sure the user is logged in to access to the Pins controller, you can use a before_action in your controller :
class PinsController < ApplicationController
before_action :authenticate_user!
(authenticate_user! being a method declared by devise).