Rails has_many :through creating new and linking in controller - ruby-on-rails

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.

Related

Why does Rails controller not have an if statement to check if destroy was successful?

I noticed that the default controller generated by rails has if statements in create and update but not in destroy
def update
#product = Product.find(params[:id])
respond_to do |format|
if #product.update_attributes(params[:product])
format.html { redirect_to #product, notice: 'Product was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
No if statement in case the destroy fails
def destroy
#product = Product.find(params[:id])
#product.destroy
respond_to do |format|
format.html { redirect_to products_url }
format.json { head :no_content }
end
end
Here is the rest of the scaffolded controller.
class ProductsController < ApplicationController
# GET /products
# GET /products.json
def index
#products = Product.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #products }
end
end
# GET /products/1
# GET /products/1.json
def show
#product = Product.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #product }
end
end
# GET /products/new
# GET /products/new.json
def new
#product = Product.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #product }
end
end
# GET /products/1/edit
def edit
#product = Product.find(params[:id])
end
# POST /products
# POST /products.json
def create
#product = Product.new(params[:product])
respond_to do |format|
if #product.save
format.html { redirect_to #product, notice: 'Product was successfully created.' }
format.json { render json: #product, status: :created, location: #product }
else
format.html { render action: "new" }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
# PUT /products/1
# PUT /products/1.json
def update
#product = Product.find(params[:id])
respond_to do |format|
if #product.update_attributes(params[:product])
format.html { redirect_to #product, notice: 'Product was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
# DELETE /products/1
# DELETE /products/1.json
def destroy
#product = Product.find(params[:id])
#product.destroy
respond_to do |format|
format.html { redirect_to products_url }
format.json { head :no_content }
end
end
end
Why does Rails controller not have an IF statement in destroy method by default?
When using create or update, there is a chance that the data will not match the requirements. For example, if you try to insert a nil value into a column with NOT NULL, or if a value isn't within a range specified by a Rails validate method.
In these instances, if we fail to save the data, we want to respond accordingly, such as with a new input form where the user can make corrections, etc. But if succeeds, we typically redirect to the show page.
When using destroy, on the other hand, we're normally removing a row from the database. Since this process doesn't include any validation, there's no (or, perhaps, very little) concern that things will go wrong. So in this situation, we don't need the if statement, and we can proceed without caution.

How to remove respond_to block from scaffold_controller template

how to customize scaffold generator #was following this link
class IdeasController < ApplicationController
before_action :set_idea, only: [:show, :edit, :update, :destroy]
# GET /ideas
# GET /ideas.json
def index
#ideas = Idea.all
end
# GET /ideas/1
# GET /ideas/1.json
def show
end
# GET /ideas/new
def new
#idea = Idea.new
end
# GET /ideas/1/edit
def edit
end
# POST /ideas
# POST /ideas.json
def create
#idea = Idea.new(idea_params)
respond_to do |format|
if #idea.save
format.html { redirect_to #idea, notice: 'Idea was successfully created.' }
format.json { render action: 'show', status: :created, location: #idea }
else
format.html { render action: 'new' }
format.json { render json: #idea.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /ideas/1
# PATCH/PUT /ideas/1.json
def update
respond_to do |format|
if #idea.update(idea_params)
format.html { redirect_to #idea, notice: 'Idea was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #idea.errors, status: :unprocessable_entity }
end
end
end
# DELETE /ideas/1
# DELETE /ideas/1.json
def destroy
#idea.destroy
respond_to do |format|
format.html { redirect_to ideas_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_idea
#idea = Idea.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def idea_params
params.require(:idea).permit(:name, :description, :picture)
end
end
How to remove all the respond_to code ?
Use respond_with to make your controllers cleaner. This apidoc and
this screencast will answer all your related questions.
Your controller methods will be as clean as this:
def update
#idea.update(idea_params)
respond_with #idea, notice: 'Idea was successfully updated.'
end
To apply that to default scaffold controller template, just copy the template content from github and put it into RAILS_ROOT/lib/templates/rails/scaffold_controller/controller.rb. Then apply the respond_with approach there.
Just do so like this.
For e.g.
respond_to do |format|
if #idea.save
format.html { redirect_to #idea, notice: 'Idea was successfully created.' }
format.json { render action: 'show', status: :created, location: #idea }
else
format.html { render action: 'new' }
format.json { render json: #idea.errors, status: :unprocessable_entity }
end
end
can be replaced with
if #idea.save
redirect_to #idea, notice: 'Idea was successfully created.'
else
render 'new
end

Why Doesn't Rails Scaffold Include Json Rendering for Edit in Controller?

This is just out of curiosity, here's a generated controller from running rails g scaffold Thing:
class ThingsController < ApplicationController
# GET /things
# GET /things.json
def index
#things = Thing.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #things }
end
end
# GET /things/1
# GET /things/1.json
def show
#thing = Thing.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #thing }
end
end
# GET /things/new
# GET /things/new.json
def new
#thing = Thing.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #thing }
end
end
# GET /things/1/edit
def edit
#thing = Thing.find(params[:id])
end
# POST /things
# POST /things.json
def create
#thing = Thing.new(params[:thing])
respond_to do |format|
if #thing.save
format.html { redirect_to #thing, notice: 'Thing was successfully created.' }
format.json { render json: #thing, status: :created, location: #thing }
else
format.html { render action: "new" }
format.json { render json: #thing.errors, status: :unprocessable_entity }
end
end
end
# PUT /things/1
# PUT /things/1.json
def update
#thing = Thing.find(params[:id])
respond_to do |format|
if #thing.update_attributes(params[:thing])
format.html { redirect_to #thing, notice: 'Thing was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #thing.errors, status: :unprocessable_entity }
end
end
end
# DELETE /things/1
# DELETE /things/1.json
def destroy
#thing = Thing.find(params[:id])
#thing.destroy
respond_to do |format|
format.html { redirect_to things_url }
format.json { head :no_content }
end
end
end
Rails includes a format block in every action except for edit... Why is this? Theoretically another app pinging the server for json would still want to show whatever is being edited, right? It's easy enough to just add in, but I am curious why they chose to do it this way.
If you want to know what you are updating, you can do it via the show action.

Rails before_filter doesn't hit database

In my application, I want to only allow user with admin privilege to access this model. So I set up and before_filter to check if the user is an Admin. The problem with this approach is that, after the admin user passes the filter, s/he won't be able to get redirect to the action. Instead, only the views are rendered, which leads to the undefined method each' for nil:NilClass error. What am I doing wrong here?
class TidbitsController < ApplicationController
before_filter :is_admin?
layout "tidbits"
# GET /tidbits
# GET /tidbits.json
protected
def is_admin?
unless current_user.admin?
flash[:error] = "You are not authorized!"
redirect_to "/" and return
end
end
def index
#tidbits = Tidbit.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #tidbits }
end
end
# GET /tidbits/1
# GET /tidbits/1.json
def show
#tidbit = Tidbit.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #tidbit }
end
end
# GET /tidbits/new
# GET /tidbits/new.json
def new
#tidbit = Tidbit.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #tidbit }
end
end
# GET /tidbits/1/edit
def edit
#tidbit = Tidbit.find(params[:id])
end
# POST /tidbits
# POST /tidbits.json
def create
#tidbit = Tidbit.new(params[:tidbit])
respond_to do |format|
if #tidbit.save
format.html { redirect_to #tidbit, notice: 'Tidbit was successfully created.' }
format.json { render json: #tidbit, status: :created, location: #tidbit }
else
format.html { render action: "new" }
format.json { render json: #tidbit.errors, status: :unprocessable_entity }
end
end
end
# PUT /tidbits/1
# PUT /tidbits/1.json
def update
#tidbit = Tidbit.find(params[:id])
respond_to do |format|
if #tidbit.update_attributes(params[:tidbit])
format.html { redirect_to #tidbit, notice: 'Tidbit was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #tidbit.errors, status: :unprocessable_entity }
end
end
end
# DELETE /tidbits/1
# DELETE /tidbits/1.json
def destroy
#tidbit = Tidbit.find(params[:id])
#tidbit.destroy
respond_to do |format|
format.html { redirect_to tidbits_url }
format.json { head :no_content }
end
end
end
in your example all your action methods are protected so maybe that's the problem?
I think you forgot to add the devise required callback filter
before_filter :authenticate_user!
before_filter :is_admin?

Rails 3.1 limit the number of child models

Hello guys I've 2 models: User(aka parent) and Profil(aka child).And I want to limit the number of profil for a user to one.
models/user.rb
class User < ActiveRecord::Base
has_one :profil
end
models/profil.rb
class Profil < ActiveRecord::Base
attr_accessible :logo
belongs_to :user
mount_uploader :logo, ImageUploader
validate :limit_profil_to_one, :on => :create
def limit_profil_to_one
if self.user.profils(:reload).count > 1
errors.add(:base, "Exceeded thing limit")
end
end
end
But when I try to create a profil I get the following error message:
NoMethodError (undefined method `profils' for nil:NilClass):
app/models/profil.rb:11:in `limit_profil_to_one'
app/controllers/profils_controller.rb:52:in `block in create'
app/controllers/profils_controller.rb:51:in `create
controllers/profils_controller.rb
# -*- encoding : utf-8 -*-
class ProfilsController < ApplicationController
# GET /factures
# GET /factures.json
def index
#profils = Profil.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #profil }
end
end
# GET /profils/1
# GET /profils/1.json
def show
#profil = Profil.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #profil }
end
end
# GET /profils/new
# GET /profils/new.json
def new
#profil = Profil.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #profil }
end
end
# GET /profils/1/edit
def edit
#profil = Profil.find(params[:id])
end
# POST /profils
# POST /profils.json
def create
#profil = Profil.new(params[:profil])
respond_to do |format|
if #profil.save
format.html { redirect_to #profil, notice: 'Profil was successfully created.' }
format.json { render json: #profil, status: :created, location: #profil }
else
format.html { render action: "new" }
format.json { render json: #profil.errors, status: :unprocessable_entity }
end
end
end
# PUT /profils/1
# PUT /profils/1.json
def update
#profil = Profil.find(params[:id])
respond_to do |format|
if #profil.update_attributes(params[:profil])
format.html { redirect_to #profil, notice: 'Profil was successfully updated.' }
format.json { head :ok }
else
format.html { render action: "edit" }
format.json { render json: #profil.errors, status: :unprocessable_entity }
end
end
end
# DELETE /factures/1
# DELETE /factures/1.json
def destroy
#profil = Profil.find(params[:id])
#profil.destroy
respond_to do |format|
format.html { redirect_to profils_url }
format.json { head :ok }
end
end
end
What I am doing wrong?
Look at line 2 in the limit_profil_to_one - self.user is nil so it is failing.
def limit_profil_to_one
if self.user.profils(:reload).count > 1 # self.user is nil
errors.add(:base, "Exceeded thing limit")
end
end
I am making some assumptions about what your app is doing, but for this post I am going to assume that your controller has a current user defined in the controller and that you are creating a Profil for that User (side: note, what is a profil? I am assuming you actually mean profile) You should set the user in the controller to the user it is supposed to be, like so.
def create
#profil = Profil.new(params[:profil])
#profil.user = current_user # however you access the currently logged in user
respond_to do |format|
if #profil.save
format.html { redirect_to #profil, notice: 'Profil was successfully created.' }
format.json { render json: #profil, status: :created, location: #profil }
else
format.html { render action: "new" }
format.json { render json: #profil.errors, status: :unprocessable_entity }
end
end
end

Resources