How to add different edit/update method into rails controller? - ruby-on-rails

The controller:
def edit
end
def update
respond_to do |format|
if #item.update(item_params)
format.html { redirect_to #item, notice: 'Item was successfully updated.' }
format.json { render :show, status: :ok, location: #item }
else
format.html { render :edit }
format.json { render json: #item.errors, status: :unprocessable_entity }
end
end
end
I want to add another methods like this. For updating only 1 column of item and i want to dont show other columns to user.
I have all neccesary views.
def another_edit
end
def another_update
respond_to do |format|
if #item.update(params[:item].permit(:amount))
format.html { redirect_to #item, notice: 'Item was successfully updated.' }
format.json { render :show, status: :ok, location: #item }
else
format.html { render :edit }
format.json { render json: #item.errors, status: :unprocessable_entity }
end
end
I thought my routes are wrong. Then tried
resources :items do
collection do
get 'add', on: :edit
end
end
and
get 'items/another_edit'
Is it possible or not? Please help me.

You need to add those endpoints in routes as "member" (not collection):
resources :items do
get :another_edit, on: :member
put :another_update, on: :member
end
Then routes will be built with "id" parameter inside.

Related

Rails update model from another controller

So I have this 2 models, Folder and Event. Folder have_one Event and Event belongs to Folder.
I want to be able to update a folder's event with new attributes at the same time as the folder. Something like this.
def update
respond_to do |format|
if #folder.update(folder_params)
#folder.event.update_attributes(status: #folder.status)
format.html { redirect_to #folder, notice: 'Folder was successfully updated.' }
format.json { render :show, status: :ok, location: #folder }
else
format.html { :edit }
format.json { render json: #folder.errors, status: :unprocessable_entity }
end
end
end
But I understand this is not very MVC compliant and also does not work. So any idea on how I can make this work ?
Thanks in advance
You can do something like:
class Folder < ActiveRecord::Base
after_save :update_event_status, on: update #Or after_update :update_event_status
def update_event_status
event.update_attributes(status: status)
end
end
write method in Model and call it in controller method. like below code.
class Folder < ActiveRecord::Base
def update_event_status(event,status)
event.update_attributes(status: status)
end
end
def update
respond_to do |format|
if #folder.update(folder_params)
update_event_status(#folder.event,#folder.status) #call methode here
format.html { redirect_to #folder, notice: 'Folder was successfully updated.' }
format.json { render :show, status: :ok, location: #folder }
else
format.html { :edit }
format.json { render json: #folder.errors, status: :unprocessable_entity }
end
end
end
Try this.

Forwarding post parameters in a redirect_to rails

In my rails app, I want the user to be able to select an option in a 'new' form, but if the option already exists, I want it to update the current option.
I have this so far in my create method:
def create
#cost = Cost.new(cost_params)
if Cost.exists?(:category => #cost.category, :option => #cost.option)
redirect_to action: 'update', id: Cost.where(:category => #cost.category, :option => #cost.option).first.id
else
respond_to do |format|
if #cost.save
format.html { redirect_to action: 'index', status: 303, notice: [true, 'Cost was successfully created.'] }
format.json { render json: #cost, status: :created, location: #cost }
else
format.html { render action: "new" }
format.json { render json: #cost.errors, status: :unprocessable_entity }
end
end
end
end
The problem is that it redirects me to, for example cost/9 url, which renders the show page. I want the id to send with the cost_params straight to the update method:
def update
#cost = Cost.find(params[:id])
respond_to do |format|
if #cost.update_attributes(cost_params)
format.html { redirect_to action: 'index', status: 303, notice: [true, 'Cost was successfully updated.'] }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #cost.errors, status: :unprocessable_entity }
end
end
end
Which should redirect to the index page.
is there any efficient way to do this?
And HTTP redirect always results in a GET request, not a POST request, so redirecting to update doesn't really make a lot of sense. That's not a Rails issue, that's just how HTTP works.
If you want to automatically update the relevant record, you have to do that from within the create action. The straightforward but lazy way would be to copy the code from update and paste it into if branch within create. The more correct way would be to extract the relevant part of update out into a separate, private method, and call that method from both create and update, something like:
def create
#cost = Cost.new(cost_params)
if Cost.exists?(:category => #cost.category, :option => #cost.option)
#cost = Cost.where(:category => #cost.category, :option => #cost.option).first
really_update
else
respond_to do |format|
if #cost.save
format.html { redirect_to action: 'index', status: 303, notice: [true, 'Cost was successfully created.'] }
format.json { render json: #cost, status: :created, location: #cost }
else
format.html { render action: "new" }
format.json { render json: #cost.errors, status: :unprocessable_entity }
end
end
end
end
def update
#cost = Cost.find(params[:id])
really_update
end
private def really_update
respond_to do |format|
if #cost.update_attributes(cost_params)
format.html { redirect_to action: 'index', status: 303, notice: [true, 'Cost was successfully updated.'] }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #cost.errors, status: :unprocessable_entity }
end
end
end

Rails 4.2 NameError in CandiesController#create

Trying to build a route that can display pages with varying information about various types of candy.
the route recognizes URL paths but want it to only show valid candy types e.g kit_kat, gummy_bear, twizzler Any other type of candy specified should generate a 404 status code
Generated a scaffold to allow anyone to add candy types but when i try to pass the valid candy types ( kit_kat etc) I get error
Rails 4.2 NameError in CandiesController#create
undefined local variable or method ` params' for #
**candy_controller.rb**
class CandiesController < ApplicationController
before_action :set_candy, only: [:show, :edit, :update, :destroy]
# GET /candies
# GET /candies.json
def index
#candies = Candy.all
end
# GET /candies/1
# GET /candies/1.json
def show
end
# GET /candies/new
def new
#candy = Candy.new
end
# GET /candies/1/edit
def edit
end
# POST /candies
# POST /candies.json
def create
if (([:kit_kat, :skittles, :m_and_ms, :herseys_kiss, :butterfinger, :gummy_bear,
:twizzler]).any? { |word| params[:title].includes?(word) })
#candy = Candy.new(candy_params)
respond_to do |format|
if #candy.save
format.html { redirect_to #candy, notice: 'Candy was successfully created.' }
format.json { render :show, status: :created, location: #candy }
else
format.html { render :new }
format.json { render json: #candy.errors, status: :unprocessable_entity }
end
end
end
end
# PATCH/PUT /candies/1
# PATCH/PUT /candies/1.json
def update
respond_to do |format|
if #candy.update(candy_params)
format.html { redirect_to #candy, notice: 'Candy was successfully updated.' }
format.json { render :show, status: :ok, location: #candy }
else
format.html { render :edit }
format.json { render json: #candy.errors, status: :unprocessable_entity }
end
end
end
# DELETE /candies/1
# DELETE /candies/1.json
def destroy
#candy.destroy
respond_to do |format|
format.html { redirect_to candies_url, notice: 'Candy was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_candy
#candy = Candy.friendly.find(params[:id])
end
# Use callbacks to share common setup or constraints between actions.
# Never trust parameters from the scary internet, only allow the white list through.
def candy_params
params.require(:candy).permit(:title, :discription)
end
end
candy.rb
class Candy < ActiveRecord::Base
extend FriendlyId
friendly_id :title, use: :slugged
end
updated candy_controller.rb
def create
if candy[:title] && !candy[:title].empty? && [:kit_kat, :skittles, :m_and_ms, :herseys_kiss, :butterfinger, :gummy_bear,
:twizzler].include?(candy[:title].to_sym)
#candy = Candy.new(candy_params)
respond_to do |format|
if #candy.save
format.html { redirect_to #candy, notice: 'Candy was successfully created.' }
format.json { render :show, status: :created, location: #candy }
else
format.html { render :new }
format.json { render json: #candy.errors, status: :unprocessable_entity }
end
end
end
end
updated code
def create
if candy_params[:title] && !candy_params[:title].empty? && [:kit_kat, :skittles, :m_and_ms, :herseys_kiss, :butterfinger, :gummy_bear,
:twizzler].include?(candy_params[:title].to_sym)
#candy = Candy.new(candy_params)
respond_to do |format|
if #candy.save
format.html { redirect_to #candy, notice: 'Candy was successfully created.' }
format.json { render :show, status: :created, location: #candy }
else
format.html { render :new }
format.json { render json: #candy.errors, status: :unprocessable_entity }
end
end
end
end
A couple of things,
First, params doesn't have :title, :title is in params[:candy][:title], or you just use candy_params[:title]
Second, the if statement could be shorter
if candy_params[:title] && !candy_params[:title].empty? && [:kit_kat, :skittles, :m_and_ms, :herseys_kiss, :butterfinger, :gummy_bear,
:twizzler].include?(candy_params[:title].to_sym)
(Go on and create the candy)
else
(Redirect with error messages | Wrong Candy Type)
end
It's always good to check the existence of the params and make sure it's not empty first, then check if it's included in the acceptable list. Notice that your original code was to compare symbol with string, so cast them to the same type and check.
UPDATE
Added else statement for redirect when :title isn't present, empty string, or wrong type

Rails, update the product right after create one

I have the web app on RoR, but the issue is once the user upload the image, the product_id is not associated with the product_attachments. Not until I proceed to next form.
Following were my controller
ProductAttachmentsController:
class ProductAttachmentsController < ApplicationController
before_action :set_product_attachment, only: [:show, :edit, :update, :destroy]
def index
#product_attachments = ProductAttachment.all
end
def show
end
def new
#product_attachment = ProductAttachment.new
end
def create
#product_attachment = ProductAttachment.new(product_attachment_params)
respond_to do |format|
if #product_attachment.save
format.html { redirect_to #product_attachment, notice: 'Product attachment was successfully created.' }
format.json {render :json => #product_attachment}
else
format.html { render :new }
format.json { render json: #product_attachment.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #product_attachment.update(product_attachment_params)
format.html { redirect_to #product_attachment.product, notice: 'Product attachment was successfully updated.' }
format.json { render :show, status: :ok, location: #product_attachment }
else
format.html { render :edit }
format.json { render json: #product_attachment.errors, status: :unprocessable_entity }
end
end
end
def destroy
#product_attachment.destroy
respond_to do |format|
format.html { redirect_to product_attachments_url, notice: 'Product attachment was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_product_attachment
#product_attachment = ProductAttachment.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def product_attachment_params
params.require(:product_attachment).permit(:product_id, :attachment)
end
end
How can I trick the create method, so it will create a product_id when I create product_attachment? Currently I need to proceed next step and it trigger update method to insert product_id in product_attachments table. Thanks!!
You can store the product attachment id in a session variable
if #product_attachment.save
session[:product_attachment] = #product_attachment.id ### HERE!
format.html { redirect_to #product_attachment, notice: 'Product attachment was successfully created.' }
format.json {render :json => #product_attachment}
else
format.html { render :new }
format.json { render json: #product_attachment.errors, status: :unprocessable_entity }
end
When you create the product (in the ProductsController ) recall the attachment and update the product_id
if #product.save
if session[:product_attachment]
ProductAttachment.find(session[:product_attachment]).update_attribute(:product_id, #product.id)
session[:product_attachment] = nil
end
...
end

Passing an argument on request.referrer

I'm building a site where a link to fill a new form can be clicked from an Event show page
<%= link_to 'Be a Contestant', new_form_path(:event_id => #event.id)%>
This creates a link like
http://localhost:3000/forms/new?event_id=2
Now if the form is filled with an error, when submitted, it returns an error
Couldn't find Event with 'id'=""
So I decided to use the request.referrer to redirect back to the previous page but it doesn't list the errors as use this method
def create
#form = Form.new(form_params)
respond_to do |format|
if #form.save
format.html { redirect_to #form, notice: 'Form was successfully created.' }
format.json { render :show, status: :created, location: #form }
else
format.html { redirect_to request.referrer }
format.json { render json: #form.errors, status: :unprocessable_entity }
end
end
end
I also tried this but to no avail.
def create
#form = Form.new(form_params)
respond_to do |format|
if #form.save
format.html { redirect_to #form, notice: 'Form was successfully created.' }
format.json { render :show, status: :created, location: #form }
else
format.html { redirect_to new_form_path(:event_id => request.referrer.params[:event_id]) }
format.json { render json: #form.errors, status: :unprocessable_entity }
end
end
end
What you probably really need to do is to add a hidden field event_id to the form because I'm betting that event_id doesn't get propagated from the #new to the #create action.
See here for more information on hidden_field_tag
You usually just render the edit view when there was an error in create:
def create
#form = Form.new(form_params)
respond_to do |format|
if #form.save
format.html { redirect_to #form, notice: 'Form was successfully created.' }
format.json { render :show, status: :created, location: #form }
else
format.html { render :edit, alert: 'Error creating ...' }
format.json { render json: #form.errors, status: :unprocessable_entity }
end
end
end

Resources