I have an HTML table that displays order items. On each table row I have a "Need By Date" field that is standalone(not in a form) input field. Whenever a user changes the date, I post this date to the server to save it against the order.
I am noticing that when I use OrderItem.update or OrderItem.update_attributes from the rails console it works, but when it is triggered from a field change event Rails does not trigger an update to the table.
#JavaScript
$(".order-item.datepicker").change ->
needby_date = $(this).val()
order_item_url = $(this).data("order-item-url")
$.ajax
type: "POST"
url: order_item_url
data:
needby_date: needby_date
My controller -
def update_needby_date
#order_item = OrderItem.find(params[:order_item_id])
#order_item.update_attribute(update_needby_date_params)
respond_to do |format|
format.js { render :nothing => true }
end
end
private
def update_needby_date_params
params.permit(:order_item_id, :needby_date)
end
As you can see in the log file, the update is not being triggered -
Started POST "/order_items/1/update_needby_date" for 127.0.0.1 at 2014-07-08 10:55:10 -0400
Processing by OrderItemsController#update_needby_date as */*
Parameters: {"needby_date"=>"07/23/2014", "order_item_id"=>"1"}
OrderItem Load (0.4ms) SELECT "order_items".* FROM "order_items" WHERE "order_items"."id" = ? LIMIT 1 [["id", "1"]]
(0.4ms) begin transaction
(0.2ms) commit transaction
Rendered text template (0.1ms)
Completed 200 OK in 16ms (Views: 3.3ms | ActiveRecord: 1.0ms)
Related
Basically, here's my controller:
class Api::ProjectsController < ApplicationController
before_action :set_params, only: [:show]
respond_to :json
def new
#project = Project.new
render layout: false
end
def create
#project = Project.new allowed_params
#project.sample = false
#project.users << current_user
if #project.save
#project.members << current_user
# redirect_to project_path(#project)
else
end
render json: {new_project: #project}
end
def set_params
#page = params[:page]
#client = params[:client]
#block = params[:block]
#block = Block.find #block if #block
end
def allowed_params
params.require(:project).permit :name, :sample
end
end
This is my html snippet:
<form ng-submit='createStream()'>
<input autofocus='autofocus' class='form-control' id='project_name' placeholder='Untitled Stream' required='required' type='text', ng-model='newProject.name'>
<br/>
<input type='submit' value='Create' class='btn btn-md btn-success'>
</form>
My popovercontroller.js.coffee
App.controller("PopoverCtrl", ($scope, Project, $location, $http) ->
$scope.initializeProject = ->
$scope.newProject = new Project();
$scope.createStream = ->
project = Project.save($scope.newProject)
$scope.projects.push(project)
)
And the services/factory
App.factory 'Project', ($resource) ->
$resource "/api/projects/:id", {id: #id},
query:
method: "POST"
isArray: false
I can save data into my DB, but I want to redirect to the show view after saving the data.
Just like the default scaffolding for RAILS, wherein after submitting the form given that it is valid... it will redirect to its show page . (e.g. localhost:3000/projects/1 with its ID.
However, the behavior now is that after submitting the form, it's not redirecting to the show page. I'm trying to get the ID of the saved record but no luck.
I tried putting $location.path('/projects/' + #id) but seems like #id is undefined and not being recognized. I'm new in manipulating JSON using Angular.
EDIT: Here's my console logs. I think JSON isn't returning? It redirects to the page where I came from. My form is in popover style so no redirection has been made.
Started POST "/api/projects" for 127.0.0.1 at 2014-01-30 06:38:30 +0800
Processing by Api::ProjectsController#create as HTML
Parameters: {"name"=>"XXX", "project"=>{"name"=>"XXX"}}
User Load (2.5ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 14 ORDER BY `users`.`id` ASC LIMIT 1
(0.2ms) BEGIN
SQL (0.3ms) INSERT INTO `projects` (`created_at`, `name`, `updated_at`) VALUES ('2014-01-29 22:38:30', 'XXX', '2014-01-29 22:38:30')
(0.2ms) INSERT INTO `projects_users` (`project_id`, `user_id`) VALUES (91, 14)
(16.4ms) COMMIT
(0.2ms) BEGIN
SQL (0.3ms) INSERT INTO `project_memberships` (`member_id`, `project_id`) VALUES (14, 91)
(1.2ms) COMMIT
Completed 200 OK in 53ms (Views: 0.5ms | ActiveRecord: 22.3ms)
Started GET "/projects/23" for 127.0.0.1 at 2014-01-30 06:38:30 +0800
Started GET "/?goto=projects/23" for 127.0.0.1 at 2014-01-30 06:38:30 +0800
Processing by MainController#index as HTML
Parameters: {"goto"=>"projects/23"}
User Load (0.4ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 14 ORDER BY `users`.`id` ASC LIMIT 1
Rendered main/index.html.haml within layouts/main (0.1ms)
Rendered application/_header.html.slim (0.5ms)
Rendered application/_footer.html.slim (0.2ms)
Completed 200 OK in 40ms (Views: 36.0ms | ActiveRecord: 0.4ms)
I'm unable to pass a variable to my controller using the data parameter of an AJAX call. What am I doing wrong?
show.html.erb
var parentStepID = 20;
$.ajax({
url: "/steps/create_branch",
type: 'GET',
data: {parent: parentStepID}
});
controller
def create_branch
parentStepID = params[:parent]
logger.debug("parentStepID: #{parentStepID}")
respond_to do |format|
format.js
end
end
The logger does not seem to get the parentStepID:
Started GET "/projects/20/steps/create_branch" for 127.0.0.1 at 2013-03-06 11:56:44 -0500
Processing by StepsController#create_branch as HTML
Parameters: {"project_id"=>"20"}
Project Load (0.1ms) SELECT "projects".* FROM "projects" WHERE "projects"."id" = ? LIMIT 1 [["id", "20"]]
####################################################################
parentStepID:
Rendered steps/create_branch.js.erb (0.1ms)
Completed 200 OK in 16ms (Views: 10.6ms | ActiveRecord: 0.1ms)
Browser console:
20 0:412
/projects/20/steps/create_branch 0:413
Also, I believe the AJAX request is working properly; I created a file called "create_branch.js.erb"' in my steps views folder and put in an alert that is successfully called.
I have an issue whereas I am trying to update a boolean field in the database with true or false based off of a checkbox.
I am using rails 3.2.2, using RVM I tried with 3.2.9 with the same result. This is in development, and I'm running postgresql as my database.
I am running in development so I am not using attr_accessible until I get to a later testing date. All similar questions I have seen on here seem to be related to forgetting to add the boolean field to attr_accessible, so letting everyone know up front that's not the issue.
From a functional standpoint this piece of the app is basically a list of events (or tasks) that the user can schedule. There is an index page that will pull a list of all the tasks they have for the day. The user can then click the checkbox next to the task and it will update the task as completed using the boolean field in question via an ajax call.
Here is the pertinent section of the index view:
=render :partial => "mktg/home/tasks"
And here is the partial _tasks.html.haml
#mktg_home_tasks
- #tasks = Mktg::Event.where('DATE(starts_at) = DATE(?)', Date.today).all
- if #tasks.empty?
You currently have no tasks...
- else
- #tasks.each do |t|
= form_for t, :index => t.id, :remote => true do |task|
= task.check_box :completed
- if task.object.completed == true
= link_to task.object.title,{}, :class => 'strike_through'
- else
= link_to task.object.title
The update method of the events controller is basically scaffolded:
def update
#event = Mktg::Event.find(params[:id])
respond_to do |format|
if #event.update_attributes(params[:event])
format.js
format.html { redirect_to #event, :notice => 'Event was successfully updated.' }
format.json { head :no_content }
else
format.html { render :action => "edit" }
format.json { render :json => #event.errors, :status => :unprocessable_entity }
end
end
end
Here is the update.js.coffee:
jQuery ->
$('#mktg_home_tasks').empty()
$('#mktg_home_past_due').empty()
$('#mktg_home_tasks').append("<%= escape_javascript(render 'mktg/home/tasks')%>")
I have the following asset running that fires off the form submittal via jquery for the checkbox:
EDIT: from first comment below my post had incorrect indentation below.
jQuery ->
$(":checkbox").live "change", ->
$(this).parents("form:first").submit()
When I run the app as is, no values get committed to the database. The console dump looks like this:
Started PUT "/mktg/events/133" for 127.0.0.1 at 2012-12-10 17:21:42 -0800
Processing by Mktg::EventsController#update as JS
Parameters: {"utf8"=>"✓", authenticity_token"=>"5ahLYhEjY2QEh6G0XOrathPXMSMaiDoCAgABpDbCZck=", "mktg_event"=>{"133"=>{"completed"=>"1"}}, "id"=>"133"}
Mktg::Event Load (0.3ms) SELECT "mktg_events".* FROM "mktg_events" WHERE "mktg_events"."id" = $1 ORDER BY starts_at ASC LIMIT 1 [["id", "133"]]
(0.2ms) BEGIN
(0.3ms) SELECT "mktg_leads".id FROM "mktg_leads" INNER JOIN "mktg_event_leads" ON "mktg_leads"."id" = "mktg_event_leads"."lead_id" WHERE "mktg_event_leads"."event_id" = 133
(0.2ms) COMMIT
Mktg::Event Load (0.5ms) SELECT "mktg_events".* FROM "mktg_events" WHERE (DATE(starts_at) = DATE('2012-12-10')) ORDER BY starts_at ASC
Rendered mktg/home/_tasks.html.haml (3.4ms)
Rendered mktg/events/update.js.coffee (4.9ms)
Completed 200 OK in 66ms (Views: 6.0ms | ActiveRecord: 4.8ms)
So I then tried adding the following before_save method to the Event model:
def set_completed_value
if self.completed == 0
self.completed = false
else
self.completed = true
end
end
With this added I am able to select the events as being completed and it works by updating the database field with true, here is the console output from that:
Started PUT "/mktg/events/133" for 127.0.0.1 at 2012-12-10 16:48:59 -0800
Processing by Mktg::EventsController#update as JS
Parameters: {"utf8"=>"✓", "authenticity_token"=>"5ahLYhEjY2QEh6G0XOrathPXMSMaiDoCAgABpDbCZck=", "mktg_event"=>{"133"=>{"completed"=>"1"}}, "id"=>"133"}
Mktg::Event Load (0.3ms) SELECT "mktg_events".* FROM "mktg_events" WHERE "mktg_events"."id" = $1 ORDER BY starts_at ASC LIMIT 1 [["id", "133"]]
(0.1ms) BEGIN
(0.4ms) SELECT "mktg_leads".id FROM "mktg_leads" INNER JOIN "mktg_event_leads" ON "mktg_leads"."id" = "mktg_event_leads"."lead_id" WHERE "mktg_event_leads"."event_id" = 133
(0.3ms) UPDATE "mktg_events" SET "completed" = 't', "updated_at" = '2012-12-11 00:48:59.877945' WHERE "mktg_events"."id" = 133
(0.5ms) COMMIT
Mktg::Event Load (0.3ms) SELECT "mktg_events".* FROM "mktg_events" WHERE (DATE(starts_at) = DATE('2012-12-10')) ORDER BY starts_at ASC
Rendered mktg/home/_tasks.html.haml (29.4ms)
Rendered mktg/events/update.js.coffee (31.0ms)
Completed 200 OK in 36ms (Views: 31.8ms | ActiveRecord: 1.8ms)
But when I deselect the checkbox to mark a completed event as not completed the database is not updated. Here is the console output:
Started PUT "/mktg/events/133" for 127.0.0.1 at 2012-12-10 16:49:14 -0800
Processing by Mktg::EventsController#update as JS
Parameters: {"utf8"=>"✓", "authenticity_token"=>"5ahLYhEjY2QEh6G0XOrathPXMSMaiDoCAgABpDbCZck=", "mktg_event"=>{"133"=>{"completed"=>"0"}}, "id"=>"133"}
Mktg::Event Load (0.2ms) SELECT "mktg_events".* FROM "mktg_events" WHERE "mktg_events"."id" = $1 ORDER BY starts_at ASC LIMIT 1 [["id", "133"]]
(0.2ms) BEGIN
(0.3ms) SELECT "mktg_leads".id FROM "mktg_leads" INNER JOIN "mktg_event_leads" ON "mktg_leads"."id" = "mktg_event_leads"."lead_id" WHERE "mktg_event_leads"."event_id" = 133
(0.1ms) COMMIT
Mktg::Event Load (0.4ms) SELECT "mktg_events".* FROM "mktg_events" WHERE (DATE(starts_at) = DATE('2012-12-10')) ORDER BY starts_at ASC
Rendered mktg/home/_tasks.html.haml (3.4ms)
Rendered mktg/events/update.js.coffee (4.8ms)
Completed 200 OK in 9ms (Views: 5.5ms | ActiveRecord: 1.2ms)
I've never had to add a before_save method like that to get a checkbox to update a boolean value in the database. So I must be doing something wrong. I know I'm close. If anyone has help or suggestions I would really appreciate it.
Thank you...
EDIT: Trying the answer given by John Naegle
I changed
= form_for t, :index => t.id, :remote => true do |task|
To
= form_for t, :index => t.id, :as => :event, :remote => true do |task|
And I get the following console output
Started PUT "/mktg/events/133" for 127.0.0.1 at 2012-12-11 09:48:14 -0800
Processing by Mktg::EventsController#update as JS
Parameters: {"utf8"=>"✓", "authenticity_token"=>"5ahLYhEjY2QEh6G0XOrathPXMSMaiDoCAgABpDbCZck=", "event"=>{"133"=>{"completed"=>"1"}}, "id"=>"133"}
Mktg::Event Load (0.2ms) SELECT "mktg_events".* FROM "mktg_events" WHERE "mktg_events"."id" = $1 ORDER BY starts_at ASC LIMIT 1 [["id", "133"]]
(0.1ms) BEGIN
(0.1ms) ROLLBACK
Completed 500 Internal Server Error in 2ms
ActiveRecord::UnknownAttributeError (unknown attribute: 133):
app/controllers/mktg/events_controller.rb:89:in `block in update'
app/controllers/mktg/events_controller.rb:88:in `update'
The record ID I am trying to change is 133 (which is the 'unknown attribute' above).
Here is the Update method with line numbers
#85 def update
#86 #event = Mktg::Event.find(params[:id])
#87
#88 respond_to do |format|
#89 if #event.update_attributes(params[:event])
#90 format.js
#91 format.html { redirect_to #event, :notice => 'Event was successfully updated.' }
#92 format.json { head :no_content }
#93 else
#94 format.html { render :action => "edit" }
#95 format.json { render :json => #event.errors, :status => :unprocessable_entity }
#96 end
#97 end
#98 end
Anything else I should try, or do you see any error in my code. Thanks again.
EDIT: Using John Naegle's answer from below I now have this working
= form_for t, :index => t.id, :as => :event, :remote => true do |task|
The above was causing the following console output and subsequent error:
"event"=>{"133"=>{"completed"=>"1"}}, "id"=>"133"}
By getting rid of :index the record ID stopped being passed incorrectly. Once I changed to this:
= form_for t, :as => :event, :remote => true do |task|
Everything started working correctly. Thanks for the help! I don't know how I'd get "unstuck" sometimes if it wasn't for this site and everyone who helps. I love this place.
It looks to me like your controller does this:
#event.update_attributes(params[:event])
But your post parameters are:
"utf8"=>"",
"authenticity_token"=>"5ahLYhEjY2QEh6G0XOrathPXMSMaiDoCAgABpDbCZck=",
"mktg_event"=>{"133"=>{"completed"=>"0"}},
"id"=>"133"}
params[:event] is empty.
I've tried looking at other answers for this but I can't seem to figure out why my redirect isn't working.
So I'm using Devise with Rails 3.1, and I'm making a shopping site. Visitors aren't allowed to add things to their cart unless they are signed in. This is what I'm having trouble with: if they aren't signed in, I want to redirect them to the Items index page. Here's what I have:
class ItemsController < ApplicationController
def add_to_cart
#item = Item.find(params[:id])
if current_user
#item.update_attributes(:cart_id => #current_cart.id)
redirect_to :back
else
redirect_to categories_path, notice: 'You must sign in to add an item to your cart.'
end
end
.
.
.
end
As of right now, when I click the link to add to cart, the method gets executed (I can see Rails loading and defining #item in the server log), and it reaches the 'else' statement, but no redirect happens.
I've already generated scaffolding for the index, new, etc. (all the RESTful actions). Also, I'm sure that I'm reaching the add_to_cart method because I've tried debugging with some puts statements. What's happening here?
EDIT:
Also, another weird thing which may be of use... The server seems to try to execute this method twice, and tries to 'get' categories twice:
Started GET "/items/3/add_to_cart" for 127.0.0.1 at 2012-01-12 16:53:11 -0800
Processing by ItemsController#add_to_cart as JS
Parameters: {"id"=>"3"}
Category Load (0.3ms) SELECT "categories".* FROM "categories"
Item Load (0.2ms) SELECT "items".* FROM "items" WHERE "items"."id" = $1 LIMIT 1 [["id", "3"]]
Redirected to http://localhost:3000/categories
Completed 302 Found in 26ms
Started GET "/items/3/add_to_cart" for 127.0.0.1 at 2012-01-12 16:53:11 -0800
Processing by ItemsController#add_to_cart as JS
Parameters: {"id"=>"3"}
Category Load (0.2ms) SELECT "categories".* FROM "categories"
Item Load (0.2ms) SELECT "items".* FROM "items" WHERE "items"."id" = $1 LIMIT 1 [["id", "3"]]
Redirected to http://localhost:3000/categories
Completed 302 Found in 25ms
Started GET "/categories" for 127.0.0.1 at 2012-01-12 16:53:12 -0800
Processing by CategoriesController#index as JS
Category Load (0.2ms) SELECT "categories".* FROM "categories"
CACHE (0.0ms) SELECT "categories".* FROM "categories"
Rendered categories/index.html.erb within layouts/application (0.0ms)
Completed 200 OK in 35ms (Views: 28.5ms | ActiveRecord: 4.2ms)
Started GET "/categories" for 127.0.0.1 at 2012-01-12 16:53:12 -0800
Processing by CategoriesController#index as JS
Category Load (0.2ms) SELECT "categories".* FROM "categories"
CACHE (0.0ms) SELECT "categories".* FROM "categories"
Rendered categories/index.html.erb within layouts/application (0.0ms)
Completed 200 OK in 37ms (Views: 30.6ms | ActiveRecord: 4.2ms)
EDIT 2 (as requested by Delba)
resources :items do
member do
get 'add_to_cart'
end
end
EDIT 3: changing the else statement to respond to javascript
respond_to do |format|
format.js { redirect_to items_path, notice: 'You must sign in to add an item to your cart.' }
end
For anyone who may need answers to this question, simply replace redirect_to statements with the following:
respond_to do |format|
format.js
end
Then, in your views under items, make a add_to_cart.js.erb page, consisting of javascript to make notices, or do whatever. Here's what I put in mine:
alert("Need to be signed in")
EDIT: Also, for the part where it executes twice: this is somewhat unrelated, but for some reason by default Rails includes duplicate Javascripts. Specifically, look at application.js: it says require jquery and require jquery_ujs. Disable one of these and you're home free.
To disable one of these javascripts:
Go to assets/application.js
Remove the comments (the // ) before require jquery, require tree .
This way, Rails doesn't assume the default and instead includes only jquery and whatever other javascripts you have in assets/javascripts
This is my route:
scope ":username" do
resources :feedbacks
end
So when I go to mydomain.com/test/feedbacks/10 it shows the correct feedback with id=10 that belongs to username=test.
But, if I go to mydomain.com/test2/feedbacks/10 it shows me the same feedback with id=10, which does NOT belong to username=test2.
How do I restrict this from happening?
I am using the Vanity gem to give me the username in the URL, this is what that route looks like:
controller :vanities do
match ':vname' => :show, :via => :get, :constraints => {:vname => /[A-Za-z0-9\-\+\#]+/}
end
Edit 1:
That is to say, for clarity's sake, when I go to mydomain.com/test/feedbacks/10 and /test2/feedbacks/10, it shows me the same view for the same record (in which case, the latter version would be wrong because it should be telling me that no such record exists, but it's not. It is just displaying the correct record for test/feedbacks/10).
Edit 2:
Here are the logs of both requests:
The right request
Started GET "/test-3/feedbacks/7" for 127.0.0.1 at 2011-09-14 02:48:15 -0500
Processing by FeedbacksController#show as HTML
Parameters: {"username"=>"test-3", "id"=>"7"}
Feedback Load (0.5ms) SELECT "feedbacks".* FROM "feedbacks" WHERE "feedbacks"."id" = ? LIMIT 1 [["id", "7"]]
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = 3 LIMIT 1
Rendered feedbacks/show.html.erb within layouts/application (36.2ms)
Completed 200 OK in 188ms (Views: 184.3ms | ActiveRecord: 1.8ms)
The wrong request
Started GET "/test2/feedbacks/7" for 127.0.0.1 at 2011-09-14 02:48:28 -0500
Processing by FeedbacksController#show as HTML
Parameters: {"username"=>"test2", "id"=>"7"}
Feedback Load (0.1ms) SELECT "feedbacks".* FROM "feedbacks" WHERE "feedbacks"."id" = ? LIMIT 1 [["id", "7"]]
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = 3 LIMIT 1
Rendered feedbacks/show.html.erb within layouts/application (37.6ms)
Completed 200 OK in 50ms (Views: 47.5ms | ActiveRecord: 1.2ms)
Your show action should look something like
def show
#user = User.find_by_username(params[:username])
if #user == current_user
...
render "show"
else
flash[:alert] = "Record doesn't exist"
redirect_to root_path
end
end
I took the liberty of adding in #Benoit's suggestion.