I have the following code in my controller:
# GET /kases/1/edit
def edit
#kase = Kase.find(params[:id])
respond_to do |format|
format.html { render :layout => 'kaseshow'} # show.html.erb
format.xml { render :xml => #kase }
format.pdf { render :layout => false }
end
end
# POST /kases
# POST /kases.xml
def create
#company = Company.find(params[:kase][:company_id])
#kase = #company.kases.new(params[:kase])
if #kase.save
UserMailer.deliver_makeakase("xxxxxx#xxxxxxxx.com", "Highrise", #kase) if params[:sendtohighrise]
UserMailer.deliver_makeakaseteam("xxxxxxxx#xxxxxxx.co.uk", "Highrise", #kase) if params[:notify_team_of_creation]
#kase.create_freeagent_project(current_user) if params[:send_to_freeagent]
redirect_to(#kase)
#flash[:notice] = 'Case was successfully created.'
flash[:notice] = fading_flash_message("Case was successfully created.", 5)
else
render :new
end
end
I am trying to make it so if the user edits a case and then selects the Send to Freeagent tickbox:
#kase.create_freeagent_project(current_user) if params[:send_to_freeagent]
then the case is resent to Freeagent (online accounting software). I'm not worried about dealing with duplicates because if the case already exists in Freeagent then the user won't need to resend it.
Is this possible?
Where is your 'update' method? The edit is only called when you are loading the data and rendering the page the user will see to edit the record. When save/update/submit is clicked on that page, it should be calling the 'update' method in the controller. So, you should be able to put that same line into the 'update' method in the true condition of the if block that looks something like this:
if #kase.update_attributes(params[:kase])
#your code would go here
#kase.create_freeagent_project(current_user) if params[:send_to_freeagent]
#the rest of the code would go here
end
It is, you could create checkbox/radio/hidden field in your edit form.
If you want to create some models for the Kase, you could as well look at accepts_nested_attributes
Related
I want to present users with separate pages/dialogs for editing their own information. However, the information is held in a single model (called User). Now I'm trying to find the best approach for handling the update calls from partials. My code currently:
def edit
render :layout=>!request.xhr?
end
def edit_password
render :layout=>!request.xhr?
end
def edit_extra
unless #user.extra
#user.build_extra
#user.extra.value = 2047
end
render :layout=>!request.xhr?
end
def update
respond_to do |format|
if #user.update_attributes(params[:user])
format.html { redirect_to #user, :notice => 'User was successfully updated.' }
format.json { head :no_content }
else
format.html { render :action => "edit", :layout=>!request.xhr? }
end
end
end
The thing is, all forms in methods (edit, edit_password and edit_extra) call the update method. However, there are two problems:
If the data parsing isn't validated, user is presented with the "edit" form, which is incorrect.
I want to have a password confirmation on extra data. User shouldn't be able to edit that information unless they supply a correct password.
I would like to make more generalized solution than just duplicating the update -code. The largest problem is rendering correct layout (edit, edit_password) based on the current action.
For now, I solved the problem by creating separate edit_section parameter that will be handled in update.
def update
respond_to do |format|
if #user.update_attributes(params[:user])
format.html { redirect_to #user, :notice => (t :actionsuccesful) }
format.json { head :no_content }
else
action = if params[:edit_section] then "edit_" + params[:edit_section] else "edit" end
format.html { render :action => action, :layout=>!request.xhr? }
end
end
end
And in forms (edit_password, etc)
=form_for(#user, :remote => true) do |f|
= hidden_field_tag :edit_section, "password"
I've got an problem with my update action for a nested resource.
In my app, my orders have many invoices.
Creating a new invoice, I correctly end up with the following url:
/orders/11/invoices/new
And when I edit the invoice, again, it's all correct:
/orders/11/invoices/3/edit
This works fine when the save is a success, however if the validation fails, it routes back to:
/invoices/3
I have the following in my invoices controller:
def update
# #order = Order.find(params[:order_id])
# #invoice = #order.invoices.find(params[:id])
#invoice = Invoice.find(params[:id])
respond_to do |format|
if #invoice.update_attributes(params[:invoice])
format.html { redirect_to(order_invoice_path(#invoice.order, #invoice), :notice => 'Invoice was successfully updated.') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #invoice.errors, :status => :unprocessable_entity }
end
end
end
def edit
#invoice = Invoice.find(params[:id])
3.times { #invoice.invoice_items.build }
end
I'm assuming I need to edit the #invoice.errors part but I don't know what to change it to?
Any help appreciated. Jx
When updating failed, you use "render" (comparing with the "redirect_to" in the succeeding path), this brings you to invoice editing path by default. You can use "redirect_to" here to keep the URI path you want, but need remembering to preserve the models' states so your users don't need to fill the entire form all over again.
A detail instruction can be found here: How to make a render :edit call show the /edit in the address bar
Yan
in your form you should add your order, like this:
<%= form_for [#order, #invoice] ... do |f| %>
...
<% end %>
And then uncomment this two lines
# #order = Order.find(params[:order_id])
# #invoice = #order.invoices.find(params[:id])
so your form will send its request to POST /orders/XX/invoices/XX
I have been trying to get to grips with jQuery and been following a railscast on adding an Ajax add review form, which works fine but I would now like to add into it the ability for a review to belong to a user as well as a venue.
Reviews controller
def create
#review = Review.create!(params[:review])
#review.venue = #venue
if #review.save
flash[:notice] = 'Thank you for reviewing this venue!'
respond_to do |format|
format.html { redirect_to venue_path(#venue) }
format.js
end
else
render :action => :new
end
end
views\reviews\create.js.erb
$("#new_review").before('<div id="flash_notice"><%= escape_javascript(flash.delete(:notice)) %></div>');
$("#reviews_count").html("<%= pluralize(#review.venue.reviews.count, 'Review') %>");
$("#reviews").append("<%= escape_javascript(render(:partial => #review)) %>");
$("#new_review")[0].reset();
I have tried changing the controller to:
def create
#review = #current_user.reviews.create!(params[:review])
#review.venue = #venue
if #review.save
flash[:notice] = 'Thank you for reviewing this venue!'
respond_to do |format|
format.html { redirect_to venue_path(#venue) }
format.js
end
else
render :action => :new
end
end
but it just wont submit, with no errors.
I think I have the models set correctly with belongs_to and has_many, I think this is a controller issue I'll add other code bits if needed.
Development log
NoMethodError (undefined method `reviews' for nil:NilClass):
app/controllers/reviews_controller.rb:14:in `create'
Thanks for any help!
It appears that your error is residing with #current_user. According to your development log, #current_user is nil when you call #current_user.reviews on it. I would say track down where this #current_user instance variable is being set and find out why it is nil. Now, what kind of authentication are you using? Most authentication plugins, especially those used by Ryan Bates of the Railscasts you mentioned, use a local variable, say just current_user, as the means to access the currently signed in user. I know I do in all my code.
So, rewrite the line as
#review = current_user.reviews.create!(params[:review])
and see if that works. If it doesn't, change it back and then track down where this #current_user is being set. Chances are good it is being set in a before_filter :method_name at the beginning of your controller.
Calling create! (with exclamation mark) will throw an exception and thus abort your create action if saving fails. Check your log/development.log for these exceptions.
Use build instead of create and lose the exclamation mark.
def create
#review = #current_user.reviews.build(params[:review])
#review.venue = #venue
if #review.save
flash[:notice] = 'Thank you for reviewing this venue!'
respond_to do |format|
format.html { redirect_to venue_path(#venue) }
format.js
end
else
render :action => :new
end
end
I have just begun Rails 3. I have generated the below code using the scaffold from Rails 3 on a table called "Logs".
The 'index' function below provides only the records associated with the current_user.id (from the session stored in the session table). The users records are only presented with the following route logged in as user = 3 (see index code below)
localhost:3000/logs
Problem: As a user, I can view a record which is not my record (being user=3) by editing the url manually to show any other record:
localhost:3000/logs/5 'this was entered by user.id=2'
Seeking Solution: How do I prevent manually hacking of the url to prevent a user viewing other user records?
class LogsController < ApplicationController
before_filter :login_required
def index
#logs = Log.where(:user_id => current_user)
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #logs }
end
Please ignore that the new function is missing from the create function below. The code below is to merely demonstrate how I put the user_id into the "Logs" table
def create
#log = Log.new(params[:log])
#log.user_id = current_user.id
respond_to do |format|
if #log.save
format.html { redirect_to(#log)}
format.xml { render :xml => #log, :status => :created, :location => #log }
else
format.html { render :action => "new" }
format.xml { render :xml => #log.errors, :status => :unprocessable_entity }
end
end
The simplest solution would be to check in the show method if the Log to display really belongs to the logged in user:
def show
#log = Log.find(params[:id])
unless #log.user_id == current_user.id
flash[:error] = "unauthorized"
redirect_to :index
end
end
But you will soon have some more things you want to restrict access to, so you should look for an authentication plugin which allows to define the access rights in a declarative manner. Maybe this one: https://github.com/be9/acl9
I am trying to add a select box to the base of my create form that decides if an action runs from the controller...if that makes any sense?
Basically the application creates a project in FreeagentCentral whenever a new project is made:
def create
#company = Company.find(params[:kase][:company_id])
#kase = #company.kases.create!(params[:kase])
respond_to do |format|
params[:send_to_freeagent] ? #kase.create_freeagent_project(current_user)
#flash[:notice] = 'Case was successfully created.'
flash[:notice] = fading_flash_message("Case was successfully created.", 5)
format.html { redirect_to(#kase) }
format.xml { render :xml => #kase, :status => :created, :location => #kase }
end
end
and within my form I have:
<%= check_box_tag :send_to_freeagent, 1 %> Create project in Freeagent?
What I would like to happen, is if the select box is checked the project is sent to Freeagent. If not, the case just gets created locally as normal but without the Freeagent data being sent.
If I use the above code, I get an exception caught error:
SyntaxError in KasesController#new
controllers/kases_controller.rb:114: syntax error, unexpected '\n'
Any idea what I am doing wrong?
I'd use
def create
#company = Company.find(params[:kase][:company_id])
#kase = #company.kases.create!(params[:kase])
#kase.create_freeagent_project(current_user) if params[:send_to_freeagent].to_bool
respond_to do |format|
# ...
end
end