Only allow owner of data to access - ruby-on-rails

I'm use devise, and belongs_to to quickly add relations. For example:
rails generate devise User
rails generate scaffold Campaign name:string user:belongs_to
Tell me please, how can I allow access to data only for the owner of this data?

Users can access their campaigns as this:
current_user.campaigns
CampaignsController
def show
#this will search only within current user campaigns.
#campaign = current_user.campaigns.find_by(id: params[:id]).
if campaign
#this campaign exists and its from current_user
...
end
end
def index
#only this user campaigns
#campaigns = current_user.campaigns
end
def new
#campaign = current_user.campaigns.build
end
def create
#This campaign is created with user_id = current_user.id
#campaign = current_user.campaigns.build(campaign_params)
#campaign.save
end
private
def campaign_params
params.require(:campaign).permit(:name)
end

Related

Add custom attributes in the mailboxer gem

I have used mailboxer gem for the messaging between users in my website.
Which is based on spree module.
I want to add the product id with the conversation so user can filter the conversations according to the products.
How can I achieve this?
Here is the code for message_controller file:
module Spree
module Admin
class MessagesController < Spree::BaseController
before_action :authenticate_spree_user!
def index
filtered_messages = Mailboxer::Message.ads_id(params[:ad_id])
end
def new
#chosen_recipient = Spree::User.find_by(id: params[:to].to_i) if params[:to]
end
def create
product_id = params[:product_id]
recipients = Spree::User.where(id: params['recipients'])
conversation = current_spree_user.send_message(recipients, params[:message][:body], params[:message][:subject], params[:product_id]).conversation
flash[:success] = 'Message has been sent!'
redirect_to '/admin/conversations'
end
private
def conversation_params
#params.require(:mailboxer_conversations).permit(:ad_id)
params.permit(:ad_id)
end
end
end
end

Rails 4 Set Value of the logged in User by default before create

I have the following models
members (id, name, company_id..)
companies (id, name, ...)
campaigns (id, company_id, ...)
When creating a Campaign i have the following
def create
#campaign = Campaign.new(campaign_params)
if #campaign.save
redirect_to campaigns_path(#campaign)
else
render :new
end
end
i have a helper method from the AppController called current_company whose id i want to set to #campagin.company_id
which is the best way to set the default logged in users company.id to every campaign created?
can i traverse through current_company and build a query like this?
#campaign = current_company.campaign.new(campaign_params)
You can use before_create callback in model for your goal:
before_create :set_default
private
def set_default
self.campaign_id ||= your_default_id
end
Or you can do same thing it in your controller directly:
def create
campaign_params[:company_id] ||= default_company_id
#campaign = Campaign.new(campaign_params)
if #campaign.save
redirect_to campaigns_path(#campaign)
else
render :new
end
end

Ruby on Rails - Unable to create a new profile for each user

I'm building an events app with users who will each have a personal profile. I've set up a few users for the site but when I try and create and/or edit a profile for each user it refers me back to a flash message "That profile doesn't belong to you!" which is in reference to my first user profile which was set up and works fine.
I'm using Devise gem for initial set up but have built out from their with my own user controller. Here's the code from that controller -
class UsersController < ApplicationController
before_action :authenticate_user!
before_action :set_user
before_action :owned_profile, only: [:edit, :update]
def new
#user = User.new
end
def show
#user = User.find(params[:id])
end
def create
end
def edit
#user = current_user #User.find_by(params[:id])
end
def update
#user = User.find_by(params[:id])
if #user.update(user_params)
redirect_to user_path, notice: "Profile successfully updated!"
else
render 'edit'
end
end
private
def user_params
params.require(:user).
permit(:name, :username, :biography, :email, :url)
end
def owned_profile
unless current_user == #user
flash[:alert] = "That profile doesn't belong to you!"
redirect_to root_path
end
end
def set_user
#user = User.find_by(params[:id])
end
end
Any assistance would be appreciated.
I would create an admin. An easy way to do this is to add a column to your users table called admin and make it a boolean. Migrate the db.
Then check to whether a user is an admin before running the owned_profile method. In that method, change: unless current_user == #user to
unless current_user == #user || current_user.admin
Then set yourself as an admin in the console, save and then freely add profiles without that callback running.
If the issue is that Users are not able to edit their own profile, then I believe it is caused by the use of find_by within set_user:
#user = User.find_by(params[:id])
Should be:
#user = User.find(params[:id])
If you truly wanted to use find_by you could do:
#user = User.find_by_id(params[:id])
Or
#user = User.find_by(id: params[:id])
Find_by used as the 2 examples above will not throw an error if a User is not found, while find will.
Sidenote: You can remove the #user assignment within the show action.
You can do it by this way.
When user signing up, automatically creates profile. Good point of this ID of user and profile tables will be the same.
rails g model profile first_name last_name email
rails g migration add_user_id_to_profiles user_id:integer
Profile.rb
belongs_to :user
User.rb
has_one :profile, dependent: :destroy
before_create :set_profile
def set_profile
build_profile(id: self.id, user_id: self.id, email: self.email)
end
GoodLuck.

Extract User's ID and insert into Posts table in ruby on rails

Experimenting with ruby on rails.. I put a new Post form on a users show page.(i.e. 0.0.0.0:3000/users/2) I'm trying to extract the user's id and insert it into a 'user_id' field in the Post table when you create a new post. So when the form is submitted from the user's page, I can link it to the user that wrote it.
models/post.rb
class Post < ActiveRecord::Base
belongs_to :user
before_save :create_user_id
def create_user_id
self.user_id = current_user
end
end
models/user.rb
class User < ActiveRecord::Base
has_many :posts
end
helpers/application_helper.rb
module ApplicationHelper
def current_user
#current_user ||= User.find(params[:id])
end
end
controllers/post_controller.rb
class PostsController < ApplicationController
def new
#post = Post.new
end
def show
#post = Post.find(params[:id])
#page_title = #post.title.capitalize
#author = User.find(#post.user_id)
#author_url = "/users/" + #post.user_id.to_s
end
def create
#post = Post.create(post_params)
if #post.save
redirect_to #post
else
render 'new'
end
end
# private
private
def post_params
params.require(:post).permit(:title, :body, :user_id)
end
end
The error I get:
Couldn't find User without an ID
Extracted source (around line #15):
#post = Post.find(params[:id])
#page_title = #post.title.capitalize
>>#author = User.find(#post.user_id)
#author_url = "/users/" + #post.user_id.to_s
end
If I test and change my application_helper.rb to this it works, and inserts 2 into the Post's user_id field. The current set up just returns nil
module ApplicationHelper
def current_user
#current_user = 2
end
end
First you want to get the current user, for now you can test using something like this:
#current_user ||= User.find(2)
Note that there will not be an :id param available on a create call, :id refers to a specific member of your resource so in this case if get http://localhost:3000/posts/1 posts would be the resource and 1 would be the param :id so this would not return the current_user you expected.
Then association should do all of the work for you and there is no need for the create_user_id method. All you would have to do is tweak your create method to
#post = current_user.posts.create(post_params)

How to add current_user to user_id to form_for in rails?

I have a form for creating materials (title, description and content - all basic). The form saves these details just fine but it doesn't save the user_id, which should be the user_id of the current_user. How do I do this? It must be easy but nothing has worked so far.
def create
#material = Material.new(params[:material])
if #material.save
flash[:success] = "Content Successfully Created"
redirect_to #material
else
render 'new'
end
end
def create
#material = Material.new(params[:material])
#material.user_id = current_user.id if current_user
if #material.save
flash[:success] = "Content Successfully Created"
redirect_to #material
else
render 'new'
end
end
There are a few different ways to do it depending on how you have your application setup. If there is a relationship between the user and materials (User has many materials), you could use that in your controller:
def create
#material = current_user.materials.new(params[:material])
# ...
end
If you don't have that relationship, I would still recommend setting it in the controller as opposed to a hidden field in the form. This will be more secure because it won't let someone tamper with the user id value:
def create
#material = Material.new(params[:material].merge(user_id: current_user))
# ...
end
Assuming you are saving the login users's object in the current_user following will work for you
#material = Material.new(params[:material])
#material.user_id = current_user.id
if #material.save
With Rails 5 and parameters needing to be permitted before objects are created, this is the simplest way to merge the current_user into the params, kudos to #Peter Brown in his answer:
def create
#discussion = current_user.materials.new(new_material_params)
# ...
end
private
def new_material_params
params.require(:material).permit(:title, :description,: content)
end
If you have nested object creation using accepts_nested_attributes_for, you need to manually merge deep into the association parameters:
class User < ApplicationRecord
has_many :discussions # Used to associate User with Discussion later
end
class Comment < ApplicationRecord
belongs_to :user
end
class Discussion < ApplicationRecord
belongs_to :user
has_many :comments
accepts_nested_attributes_for :comments
end
class DiscussionsController < ApplicationController
def create
# Merge the params[:discussion][:user_id] by using the relationship's #new
#discussion = current_user.discussion.new(new_discussion_params)
end
private
# Sanitized params for creation, not editing
def new_discussion_params
params.require(:discussion)
.permit(:title, :user_id,
comments_attributes: [:id, :content, :discussion_id, :user_id])
.tap do |discussion_params|
# Require the association parameters, and if they exist,
# set :user_id for each.
discussion_params.require(:comments_attributes).each do |i, comment|
comment.merge!(user_id: current_user.id)
end
end
end
end
Heads up: Setting (or overwriting!) what will be params[:discussion][:comments_attributes]["0"][:user_id] works fine for creation. But if you allow editing deep hierarchies in addition to creation, make sure you don't accidentally overwrite all the :user_ids with the current user.

Resources