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
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
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
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
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.
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.