Allow admin to post as user in Rails app - ruby-on-rails

I'm building a rails app where users can log on and see a table of their SAT test scores. Users "has_many" scores and Scores "belongs_to" users. Currently it is set up so that the user can post their own scores. What I want is for an admin to post the scores and the user will just see the table on their show page. The "admin" is just a boolean field in users that I set to true for the admins.
Here is the scores controller:
class ScoresController < ApplicationController
def index
#scores = Score.all
end
def show
#score = Score.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #score }
format.js
end
end
def new
#score = Score.new
end
def create
#score = current_user.scores.new(params[:score])
#user = current_user
respond_to do |format|
if #score.save
format.html { redirect_to #score.user, notice: 'Score was successfully created.' }
format.json { render json: #score, status: :created, location: #score }
else
format.html { render action: 'new' }
format.json { render json: #score.errors, status: :unprocessable_entity }
end
end
end
def update
#score = Score.find(params[:id])
respond_to do |format|
if #score.update(params[:score])
format.html { redirect_to #score.user, notice: 'Score was successfully updated.' }
format.json { render action: 'show', status: :ok, location: #score }
else
format.html { render action: 'edit' }
format.json { render json: #score.errors, status: :unprocessable_entity }
end
end
end
def edit
#score = Score.find(params[:id])
end
def destroy
#score = Score.find(params[:id])
if #score.present?
#score.destroy
end
redirect_to #score.user
end
end
I know I'd have to change the scores controller so that it didn't rely on current_user to create and edit scores. I'm just not sure how to implement that. Let me know if you need more info! Thanks.

First, you'll need to add a select tag in your view to select which user you want to post as:
- if current_user.is_admin?
= f.select :user_id, options_for_select(User.all.map{ |u| [u.username, u.id] })
- else
= f.hidden_field :user_id, value: current_user.id
Then, on the server-side, we will double-check that current_user is an admin to allow the creation of a Score for another User:
def create
#score = Score.new(params[:score])
if current_user.id != #score.user_id # Someone is trying to create a Score for someone else!
#score.errors.add(:user_id, "You shall not create Score for other users than you, you evil hacker!") unless current_user.is_admin?
end
respond_to do |format|
if #score.save
format.html { redirect_to #score.user, notice: 'Score was successfully created.' }
format.json { render json: #score, status: :created, location: #score }
else
format.html { render action: 'new' }
format.json { render json: #score.errors, status: :unprocessable_entity }
end
end
end
I omitted the part #user = current_user because usually current_user is a helper method than can be accessed directly in the views, so instead of using #user in the create view, use current_user instead.

Related

Not able to update data in database form

I am getting error - undefined method collect for nil:NilClass, but I am able to render option list from another database table, and also able to save data in stage table but not able to update it.
I am rendering option list form responsibility table in stage form field responsibility option and saves that option into stage table.
stages_controller.rb
def index
redirect_to project_path(#project)
end
def show
end
def new
#stage = Stage.new
#responsibilities = #project.responsibilities
end
def edit
end
def create
#responsibilities = #project.responsibilities
#stage = #project.stages.build(stage_params)
respond_to do |format|
if #stage.save
format.html { redirect_to project_path(#project), notice: 'Stage was successfully created.' }
format.json { render :show, status: :created, location: #stage }
else
format.html { render :new }
format.json { render json: #stage.errors, status: :unprocessable_entity }
end
end
end
def update
#responsibilities = #project.responsibilities
respond_to do |format|
if #stage.update(stage_params)
format.html { redirect_to project_stages_url, notice: 'Stage was successfully updated.' }
format.json { render :show, status: :ok, location: #stage }
else
format.html { render :edit }
format.json { render json: #stage.errors, status: :unprocessable_entity }
end
end
end
def destroy
#stage.destroy
respond_to do |format|
format.html { redirect_to project_stages_url, notice: 'Stage was successfully deleted.' }
format.json { head :no_content }
end
end
private
def set_stage
#stage = Stage.find(params[:id])
end
def find_project
#project = Project.find(params[:project_id])
end
your edit method is empty, so #responsibility has no content (null), you can put some code for example (from your other method)
def edit
#project = Project.find(params[:id])
#responsibilities = #project.responsibilities
...
end
The issue here is that #responsibilities is not defined in your partial.
You should pass the local variable to the partial like this -
<%= render partial: "form", locals: {responsibilities: # responsibilities} %>
and then you can use responsibilities inside the form partial
More about passing variable to partials

change behaviour of Create if record with same attribute exists

I'm building an app like reddit where you add a Submission to a specific user page. Submission has a few attribute including an attribute called url.
I want to check when adding a new submission if already a submission with that same url exists for that specific page, and if it exist, vote for it instead of creating it as a new submission. If not, just add it as a new submission. I'm using the act_as_votable gem here.
Here is the create method:
def create
#user = User.friendly.find(params[:user_id])
#submission = #user.submissions.new(submission_params)
#submission.member_id = current_user.id
#submission.creator_id = #user.id
#submission.is_viewed = false
#submission.get_thumb_and_title_by_url(#submission.url)
respond_to do |format|
if #submission.save
format.html { redirect_to #user, notice: 'Submission was
successfully created.' }
format.json { render :show, status: :created, location: #submission }
else
format.html { render :new }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
you should take a look at https://apidock.com/rails/v4.0.2/ActiveRecord/Relation/find_or_create_by and https://apidock.com/rails/v4.0.2/ActiveRecord/Relation/find_or_initialize_by
Now on your code we can make changes like
def create
#user = User.friendly.find(params[:user_id])
#submission = #user.submissions.find_or_initialize_by(submission_params)
if #submission.id.present?
# What to do if the record exists
else
# if its a new record
#submission.member_id = current_user.id
#submission.creator_id = #user.id
#submission.is_viewed = false
#submission.get_thumb_and_title_by_url(#submission.url)
end
respond_to do |format|
if #submission.save
format.html { redirect_to #user, notice: 'Submission was
successfully created.' }
format.json { render :show, status: :created, location: #submission }
else
format.html { render :new }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
I hope that this can put you on the right track
Happy Coding

Rails mailer: create object and access the id of the object inside a mailer view template

I'm creating and object inside a controller:
def create
#item = Item.new(item_params)
if #item.save
respond_to do |format|
format.html { redirect_to index_path, notice: "Created"}
format.json { render :'shows/show', status: :created, location: #item }
end
ModelMailer.delay.new_post(#user)
else
format.html { render :new }
format.json { render json: #item.errors, status: :unprocessable_entity }
end
end
end
this is the mailer method:
def new_post(user)
#user = User.find(user.id)
attachments.inline["logo.png"] = File.read("#{Rails.root}/app/assets/images/logo.png")
mail(:to => #follow.email,
:subject => "Created a new post")
end
I would like to add the item.id thats is created to the mailer so I can access it in the email view template. Any ideas on how to implement this?
Just pass it. I don't actually see where you save the record so presumably your create example is incomplete, but once you have that working you can do...
ModelMailer.new_post(#user, #item.id).deliver_later
Then on the mailer
def new_post(user, item_id)
#item_id = item_id
The #item_id will be available in the view.
And to fix your controller create method (which is still wrong), it should be...
def create
#item = Item.new(item_params)
if #item.save
respond_to do |format|
format.html { redirect_to index_path, notice: "Created"}
format.json { render :'shows/show', status: :created, location: #item }
ModelMailer.delay.new_post(#user, #item.id)
end
else
respond_to do |format|
format.html { render :new }
format.json { render json: #item.errors, status: :unprocessable_entity }
end
end
end

How to pass id from create action to another action?

Ok I have two methods
def join_group
#user = User.find(current_user[:id])
#group = Group.find(params[:id])
respond_to do |format|
if #user.groups << #group
format.html {redirect_to #group}
format.js
else
format.html { render :index}
end
end
end
def create
#group = Group.new(group_params)
#group.created_by = current_user.id
respond_to do |format|
if #group.save
format.html { redirect_to #group }
format.js
format.json { render :show, status: :created, location: #group }
else
format.html { render :new }
format.json { render json: #group.errors, status: :unprocessable_entity }
end
end
end
And I want to make that after create action join_group is called. I was trying after_action :join_group, only: [:create] but i don't know how to pass id into join_group and I ended up with ActiveRecord::RecordNotFound (Couldn't find Group with 'id'=):
Instead of a completely separate action to add the user after you create it you could just set it up in the create method.
def create
#adds user to the group and builds it like you have it.
#group = current_user.groups.build(group_params.merge(created_by: current_user.id)
respond_to do |format|
if #group.save
format.html { redirect_to #group }
format.js
format.json { render :show, status: :created, location: #group }
else
format.html { render :new }
format.json { render json: #group.errors, status: :unprocessable_entity }
end
end
end
But if you do want it separate I would add it as a method on the group and just pass the User ID to it.

Rails has_many :through creating new and linking in controller

I have a website I am making that tracks a users companies through employments. I need to know what I am doing wrong because when I make a new user company the user doesn't know about it.
companies_controller.rb
class CompaniesController < ApplicationController
# GET /companies
# GET /companies.json
def index
#companies = current_user.companies
respond_to do |format|
format.html # index.html.erb
format.json { render json: #companies }
end
end
# GET /companies/1
# GET /companies/1.json
def show
#company = Company.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #company }
end
end
# GET /companies/new
# GET /companies/new.json
def new
#company = Company.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #company }
end
end
# GET /companies/1/edit
def edit
#company = Company.find(params[:id])
end
# POST /companies
# POST /companies.json
def create
#company = Company.new(params[:company])
current_user.employments.create!(company_id: #company.id)
respond_to do |format|
if #company.save
format.html { redirect_to #company, notice: 'Company was successfully created.' }
format.json { render json: #company, status: :created, location: #company }
else
format.html { render action: "new" }
format.json { render json: #company.errors, status: :unprocessable_entity }
end
end
end
# PUT /companies/1
# PUT /companies/1.json
def update
#company = Company.find(params[:id])
respond_to do |format|
if #company.update_attributes(params[:company])
format.html { redirect_to #company, notice: 'Company was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #company.errors, status: :unprocessable_entity }
end
end
end
# DELETE /companies/1
# DELETE /companies/1.json
def destroy
#company = Company.find(params[:id])
#company.destroy
respond_to do |format|
format.html { redirect_to companies_url }
format.json { head :no_content }
end
end
end
The problem is within your create action, specifically the line
current_user.employments.create!(company_id: #company.id)
this is executed before the company record is saved so it doesn't have an id (== nil). Just move that line after
if #company.save
and it should attach it to the current_user via the :through relationship.

Resources