I have multiple Carrierwave attachment fields in my model which I would like to be able remove in my show view. As there are multiple fields I pass a parameter to my controller method so it knows which file to remove:
def remove_attachment
post = Post.find(params[:id])
post["remove_#{params[:attachment]}!"]
post.save
redirect_to post
end
However, the following line does not work post["remove_#{params[:attachment]}!"]? Not sure where I am going wrong here?
I've tested the following which does work:
def remove_attachment
post = Post.find(params[:id])
post.remove_compliance_guide! # one of the attachment fields
post.save
redirect_to post
end
I realise that I could do the below but I think my first solution is cleaner.
def remove_attachment
post = Bid.find(params[:id])
if params[:attachment] == 'compliance_guide'
post.remove_compliance_guide!
elsif params[:attachment] == 'compliance_other'
post.remove_compliance_other!
elsif params[:attachment] == 'compliance_agreement'
post.remove_compliance_agreement!
end
post.save
redirect_to post
end
Just in case I've made a mistake somewhere else:
route: post 'posts/:id/remove_attachment', to: 'posts#remove_attachment'
view link: link_to 'Remove', { controller: 'post', action: "remove_attachment", attachment: 'compliance_guide', id: #post.id }, method: 'post', class: "file-remove right"
You can use send to invoke a method by passing its name as a string:
def remove_attachment
post = Post.find(params[:id])
post.send("remove_#{params[:attachment]}!")
post.save
redirect_to post
end
Note that a NoMethodError will be raised if the attachment doesn't exist. You could work around that using something like:
if post.respond_to?("remove_#{params[:attachment]}!")
post.send("remove_#{params[:attachment]}!")
post.save
end
Related
hoping someone can help. I've been searching through other "param is missing" questions, but can't seem to figure out what's wrong.
In my routes file I have this nested resource "actions"
resources :jobs do
resources :actions
end
The associated models. Ignore "action_reference". That's something else.
class Job < ActiveRecord::Base
has_many :actions
end
class Action < ActiveRecord::Base
belongs_to :job
belongs_to :action_reference
end
And I'm trying to create a new action by making a POST request using button_to
Here's the ActionsController
class ActionsController < ApplicationController
before_action :set_job
before_action :set_action, only: [:show, :edit, :update]
# GET /jobs/:job_id/actions/:id
def show
end
# GET /jobs/:job_id/actions/new
def new
#action = Action.new
end
# GET /jobs/:job_id/actions/:id/edit
def edit
end
# POST /jobs/:job_id/actions/
def create
#action = #job.actions.create(action_params)
if #action.save
flash[:success] = "Next step successfully added."
redirect_to jobs_path
else
flash[:danger] = #action.errors.full_messages.join(", ")
redirect_to new_job_action_path
end
end
# PATCH to /jobs/:job_id/actions/:id
def update
if #action.update(action_params)
flash[:success] = "Next step successfully updated."
redirect_to jobs_path
else
flash[:danger] = #action.errors.full_messages.join(", ")
redirect_to edit_job_action_path
end
end
private
def set_job
#job = Job.find(params[:job_id])
end
def set_action
#action = Action.find(params[:id])
end
def action_params
params.require(:action).permit(:action_reference_id, :job_id, :completed_at, :next_action_date)
end
end
And here's my button_to
<%= button_to answer[:text], post_action_jobs_path(#job), method: "post", params: { action: { action_reference_id: answer[:action_reference_id], job_id: #job_id , completed_at: answer[:action_completed_at], next_action_date: answer[:next_action_date] } }, type: "button", class: "btn btn btn-info btn-block" %>
I know the problem has something to do with the arguments I'm passing to the post_action_jobs_path in the view or the ones I'm passing to action_params in the controller, but I can't figure it out.
When I run this I get the error:
undefined method `permit' for "create":String Did you mean? print
I saw some thread a little while ago saying something about "action" being a reserved word in Rails, so you have to use something else, but if that's true I'm not sure how to go about that.
Any help would be greatly appreciated :)
Yes unfortunately this is due to "action" being an existing method inside rails controllers. It is used to get the name of the action that has been called. In this case "action" will equal the string "create".
One thing you could do would be to rename you Action model to JobAction and use params.require(:job_action)
Sadly I couldn't seem to find away around this, so I renamed my "actions" table and replaced every reference to "action" with a different word "step". Now it works!
I can hit the importers#import_vendor_ledger action but I can't seem to hit the importers#import_chart_of_accounts action via the redirect_based_on(arg) method inuploaders#upload_file. Please help!
NOTE: I left out some code that I didn't think was necessary to see
My code:
routes.rb
resources :uploaders do
collection { post :upload_file }
end
resources :importers do
collection { post :import_vendor_ledger, :import_chart_of_accounts }
end
index.html.haml
#chart_of_accounts
= form_tag upload_file_uploaders_path, multipart: true do
= hidden_field_tag :account, "chart_of_accounts"
= file_field_tag :file
= submit_tag 'Upload Chart of Accounts'
#vendor_ledger
= form_tag upload_file_uploaders_path, multipart: true do
= hidden_field_tag :account, "vendor_ledger"
= file_field_tag :file
= submit_tag 'Upload'
uploaders_controller.rb
class UploadersController < ApplicationController
include Excel
def upload_file
uploaded_io = params[:file]
if uploaded_io.path.downcase.end_with?(xlsx_extension)
save_to_storage(uploaded_io)
flash[:success] = 'File uploaded successfully!'
redirect_based_on_(params) # this is where it should call the action
else
flash[:warning] = 'ERROR: The file you upload MUST be an ".xlsx" excel file!'
redirect_to root_url
end
end
private
def redirect_based_on_(_params)
case _params[:account]
when "vender_ledger"
redirect_to import_vendor_ledger_importers_path and return
when "chart_of_accounts"
redirect_to import_chart_of_accounts_importers_path and return
end
end
end
importers_controller.rb
class ImportersController < ApplicationController
include Excel
def index
end
def show
end
def import_vendor_ledger # I can hit this action
puts "hits vendor ledger import"
end
def import_chart_of_accounts # but I can't hit this action
puts "hits chart of accounts import"
end
EDIT #1: even if I explicitly call redirect_to import_chart_of_accounts_importers_path in uploaders#upload_file it still doesn't hit the importers#import_chart_of_accounts action
EDIT #2: after inspecting more, it seems that importers#import_chart_of_accounts action IS being hit, but none of the functions in the action is being called
Change your route to something like this:
resources :importers do
collection do
get :import_vendor_ledger
get :import_chart_of_accounts
end
end
EDIT: Since you are redirecting to those two paths, I believe, you need those to be GET routes. Since redirect_to issues a 301 request which will be GET request.
This is a possible duplicate, but I have read and tried nearly all suggestions, but I keep getting the error on the New action view. I am using Rails 5.
I have tried the following:
private
def ph_params
params.require(:ph).permit(:amount)
end
And also tried the following, and the error disappeared, but my values were not saving to database, only shows Nil:
private
def ph_params
params.permit(:amount)
end
My controller:
class PhsController < ApplicationController
def index
end
def new
#ph = Ph.new(ph_params)
end
def create
#ph = Ph.new(ph_params)
respond_to do |format|
if #ph.save
format.html { redirect_to #ph }
else
format.html { render "new" }
end
end
end
def show
#ph = Ph.find(params[:id])
end
private
def ph_params
params.require(:ph).permit(:amount)
end
end
new.html.erb form start
<%= simple_form_for #ph, url: phs_path do |f| %>
Model
class Ph < ApplicationRecord
end
I might be missing something. Your assistance is appreciated, thank you in advance.
Modify your new action to
def new
#ph = Ph.new
end
The reason you're getting the error is because when you hit the route phs/new, no key ph is passed in the params hash to the controller but you're trying to access params[:ph][:amount] which is the return value of ph_params. This is why the error 'param is missing or the value is empty' occurs.
If you want to know what values were passed in the params has for every request, add the following line to your application.html.erb
<%= params.inspect %>
You'll probably find a hash with two keys {"controller" => "phs", "action" => "new"} in the new page.
However, when you try to create a new ph object, you will find a key ph in your params hash.
By the way, I think you don't quite understand strong parameters. I would suggest you to read http://api.rubyonrails.org/classes/ActionController/StrongParameters.html
I have some problems with an Ajax function. I got an error 500 from the server.
The Ajax function looks like this:
$.ajax({
type: "POST",
url: "<%= url_for(:controller => "movies", :action => "test") %>",
data: {inputtag: tag }
})
In my movies controller, I have this function
# Fügt dem Video einen Tag hinzu
def test
#tag = Tag.new
if request.post?
#tag.update_attributes(params[:inputtag])
if #tag.save
redirect_to :back
else
redirect_to :back
end
end
end
So, I do not know Why I got this error:
http://lvh.me/movies/test 500 (Internal Server Error)
You are missing the entry in your routes.rb file
resources :movies do
collection do
get 'test'
end
end
500 status is not about routing. Check your controller action, specifically this.
#tag.update_attributes(params[:inputtag])
You are trying to update a record that does not exist and you are not using the strong parameters of Rails properly. So try this instead.
def test
#tag = Tag.create tag_params
redirect_to :back
end
private
# If your tag model looks like: Tag(id: integer, inputtag: string)
def tag_params
params.require(:tag).permit(:inputtag)
end
I'm having what I assume must be a simple problem but I just can't figure it out. I'm trying to update an attribute in one model when another is created.
In my view:
<%= link_to 'Click here to rate this user', new_user_review_path(:user_id => request.user.id, :gigid => request.gig.id), remote: true %>
Which passes params :gigid and :user_id
Than my controller:
def new
#review = Review.new
#gig = Gig.find(params[:gigid])
end
def create
#review = #user.reviews.new review_params
#review.reviewed_id = current_user.id
if #review.save
#gig.update(reviewed: true)
respond_to do |format|
format.html {redirect_to session.delete(:return_to), flash[:notice] = "Thankyou for your rating!"}
format.js
end
else
render 'new'
end
end
But I get undefined method 'update'for nil:NilCLass:
I know the params are passing and the 'Gig' can be updated as :
def new
#review = Review.new
Gig.find(params[:gigid]).update(reviewed: true)
end
updates the attribute fine, but when I click 'New review' not when the review is actually created.
Adding :
def create
#review = #user.reviews.new review_params
#review.reviewed_id = current_user.id
if #review.save
Gig.find(params[:gigid]).update(reviewed: true)
etc etc etc
gives me the same undefined method 'update'for nil:NilCLass:
I have tried with find_by_id instead of find which makes no difference.
EDIT:
def create
#gig = Gig.find params[:gigid]
#review = #user.reviews.new review_params
#review.reviewed_id = current_user.id
if #review.save
#gig.update(reviewed: true)
etc etc etc
Doesn't work either. I get no errors, but the gig ID is still 'nil'.
The params are passing to the 'New' action but not the 'Create' action. I feel this should be very easy but I'm just not seeing it at the moment.
But I get undefined method 'update'for nil:NilCLass:
The error is that you have not defined #gig in your create action.
Since Rails is built on HTTP, and HTTP is stateless, you have to set the "instance" variables with each new request:
def new
#review = Review.new
#gig = Gig.find params[:gigid]
end
def create
#gig = Gig.find params[:gigid]
#review = #user.reviews.new review_params
A much better pattern for you would be to use the after_create callback in your Review model:
#app/models/review.rb
class Review < ActiveRecord::Base
belongs_to :gig #-> I presume
after_create :set_gig
private
def set_gig
self.gig.update(reviewed: true)
end
end
--
If you wanted to make the Gig update within your current setup, you'll be best sending the gig_id param through the request (not the link):
#app/views/reviews/new.html.erb
<%= form_for [#user, #review] do |f| %>
<%= f.hidden_field :gig_id, #gig.id %> #-> params[:reviews][:gig_id]
...
<% end %>
This will make params[:review][:gig_id] available in the create action, with which you'll be able to use in your code.
The problem is, you never assigned a value to #gig in your create method. I can't see your form, but you need something like this in your create method:
#gig = Gig.find params[:gigid]
Assuming that you're passing the parameter :gigid to #create
In the second example you showed, I'm not sure what's going on, but you should be getting a ActiveRecord::RecordNotFound exception on the find().
Try the below code for update operation.
gig_record = Gig.find_by_id(params[:gigid])
gig_record.update_attribute(reviewed: true) unless gig_record.blank?