How to destroy chatrooms for current_user with ActionCable? - javascript

I created a chatroom feature with Rails 5.1, the issue that I am having, is that I'm unable to destroy the chatrooms created by the current_user. How can I fix my code to destroy the chatroom and the users within the thread by the owner of the chatroom?
chatroom.rb
class Chatroom < ApplicationRecord
has_many :chatroom_users, dependent: :destroy
has_many :users, through: :chatroom_users
has_many :messages, dependent: :destroy
belongs_to :category
validate :max_channel_check, on: :create
validates :category, presence: true
scope :public_channels, ->{ where(direct_message: false) }
scope :direct_messages, ->{ where(direct_message: true) }
scope :recent, -> {where('created_at >= :thirty_minutes_ago', thirty_minutes_ago: Time.now - 30.minutes.ago)}
def max_channel_check
if current_user.chatrooms.count >= 5
errors.add(:base, "You've created the maximum amount of channels, please delete some of the channels you have open.")
end
end
def self.direct_message_for_users(users)
user_ids = users.map(&:id).sort
name = "DM:#{user_ids.join(":")}"
if chatroom = direct_messages.where(name: name).first
chatroom
else
# create a new chatroom
chatroom = new(name: name, direct_message: true)
chatroom.users = users
chatroom.save
chatroom
end
end
end
chatrooms_controller.rb
class ChatroomsController < ApplicationController
before_action :set_chatroom, only: [:show, :edit, :update, :destroy]
include ChatroomsHelper
include UsersHelper
# GET /chatrooms
# GET /chatrooms.json
def index
#chatrooms = Chatroom.public_channels.page(params[:page]).per(40)
#chatroom_categories = Chatroom.public_channels.page(params[:page]).per(26)
end
# GET /chatrooms/1
# GET /chatrooms/1.json
def show
#messages = #chatroom.messages.order(created_at: :desc).limit(100).reverse
#chatroom_user = current_user.chatroom_users.find_by(chatroom_id: #chatroom.id)
end
# GET /chatrooms/new
def new
#chatroom = Chatroom.new(user_id: current_user.id)
end
# GET /chatrooms/1/edit
def edit
end
# POST /chatrooms
# POST /chatrooms.json
def create
#chatroom = current_user.chatrooms.build(chatroom_params)
respond_to do |format|
if #chatroom.save
#chatroom.chatroom_users.where(user_id: current_user.id).first_or_create
format.html {redirect_to #chatroom, notice: 'Chatroom was successfully created.'}
format.json {render :show, status: :created, location: #chatroom}
else
format.html {render :new}
format.json {render json: #chatroom.errors, status: :unprocessable_entity}
end
end
end
# PATCH/PUT /chatrooms/1
# PATCH/PUT /chatrooms/1.json
def update
respond_to do |format|
if #chatroom.update(chatroom_params)
format.html {redirect_to #chatroom, notice: 'Chatroom was successfully updated.'}
format.json {render :show, status: :ok, location: #chatroom}
else
format.html {render :edit}
format.json {render json: #chatroom.errors, status: :unprocessable_entity}
end
end
end
# DELETE /chatrooms/1
# DELETE /chatrooms/1.json
def destroy
if current_user == #chatroom.user
#chatroom.destroy
respond_to do |format|
format.html {redirect_to chatrooms_url, notice: 'Chatroom was successfully destroyed.'}
format.json {head :no_content}
end
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_chatroom
#chatroom = Chatroom.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def chatroom_params
params.require(:chatroom).permit(:name, :category_id, :chat_name_color, :user_id)
end
schema.rb
create_table "chatroom_users", force: :cascade do |t|
t.bigint "chatroom_id"
t.bigint "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.datetime "last_read_at"
t.index ["chatroom_id"], name: "index_chatroom_users_on_chatroom_id"
t.index ["user_id"], name: "index_chatroom_users_on_user_id"
end
create_table "chatrooms", force: :cascade do |t|
t.bigint "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "direct_message", default: false
t.string "name"
t.string "chat_name_color"
t.integer "category_id"
t.index ["category_id"], name: "index_chatrooms_on_category_id"
t.index ["user_id"], name: "index_chatrooms_on_user_id"
end
chatroom_user.rb
class ChatroomUser < ApplicationRecord
belongs_to :chatroom
belongs_to :user
before_create :set_last_read
def set_last_read
self.last_read_at = Time.zone.now
end
end

In your Destroy action you have if current_user == #chatroom.user, not entirely sure #chatroom.user will bring out the correct info, but to give the creator of a chatroom the ability to delete a chatroom, you might want to add a creator column to chatroom table and save maybe the username, then in your destroy action compare current_user.name == #chatroom.creator.
Or better still remove the condition in the destroy action and make the delete button only be visible if current_user.name == #chatroom.creator

Related

Rails 5.1.2 Ajax remote: true not working

I would like to implement ajax to create a post, without recharging the page and not going to the show (I following a tutorial) but is not working.
in the _form.html.haml you can see remote:true in the form helper
= form_for #post,remote: true do |f|
- if #post.errors.any?
#error_explanation
%h2= "#{pluralize(#post.errors.count, "error")} prohibited this post
from being saved:"
%ul
- #post.errors.full_messages.each do |message|
%li= message
.mdl-textfield.mdl-js-textfield.full-width
= f.text_area :body, class:"mdl-textfield__input"
= f.label :body, "Comparte con la Comunidad", class:"mdl-
textfield__label"
.actions.text-right
= f.submit 'Publicar', class:"mdl-button mdl-js-button mdl-button--
raised mdl-button--colored"
however when the post is created, the application redirect to the show of the post created recently in html format, it should be stay in the form.
I don't know if the version of Rails 5.1.2 has a issue, but in Rails 4 with only typing remote: true the application stay in the form after the submit action.
post controller:
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
# GET /posts
# GET /posts.json
def index
#posts = Post.all
end
# GET /posts/1
# GET /posts/1.json
def show
end
# GET /posts/new
def new
#post = Post.new
end
# GET /posts/1/edit
def edit
end
# POST /posts
# POST /posts.json
def create
#post = current_user.posts.new(post_params)
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: #post }
else
format.html { render :new }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /posts/1
# PATCH/PUT /posts/1.json
def update
respond_to do |format|
if #post.update(post_params)
format.html { redirect_to #post, notice: 'Post was successfully updated.' }
format.json { render :show, status: :ok, location: #post }
else
format.html { render :edit }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.json
def destroy
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url, notice: 'Post was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
#post = Post.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def post_params
params.require(:post).permit(:body)
end
end
also I have a show.js.erb file to render a view to see the body of the post after he is created.
show.js.erb
$('#posts').append("<%= render j #post %>")
_post.haml
%article
=post.body
Done! in the post controller is missing to respond a JS format and the show.js.erb the render method has bad syntax
1) post controller: add format.js
def create
#post = current_user.posts.new(post_params)
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: #post }
format.js { render :show }
else
format.html { render :new }
format.json { render json: #post.errors, status: :unprocessable_entity }
format.js { }
end
end
end
2) show.js.erb: the J it should be before render
$("posts").append(<%= j render #post %>)

Restriction for post to the map display

i'm currently building a web app, and I encounters some problems.
I want the map display posts that are pushed (so push == true). For that, i'd try a lot of conditions, but it's never working. I feel I am not far from the goal, but for now, the map no reference points.
posts controller :
class PostsController < ApplicationController
before_action :authenticate_user!
before_action :set_post, only: [:show, :edit, :update, :destroy]
before_action :owned_post, only: [:edit, :update, :destroy]
# GET /posts
# GET /posts.json
def index
#posts = Post.all.order("push_updated_at DESC")
if #posts.push == true
#hash = Gmaps4rails.build_markers(#posts) do |post, marker|
marker.lat post.latitude
marker.lng post.longitude
end
end
end
# GET /posts/1
# GET /posts/1.json
def show
end
# GET /posts/new
def new
#post = current_user.posts.build
end
# GET /posts/1/edit
def edit
end
# POST /posts
# POST /posts.json
def create
#post = current_user.posts.build(post_params)
respond_to do |format|
if #post.save
#post.update(push: false)
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: #post }
else
format.html { render :new }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /posts/1
# PATCH/PUT /posts/1.json
def update
#post = Post.find(params[:id])
respond_to do |format|
if #post.update(post_params)
format.html { redirect_to #post, notice: 'Post was successfully updated.' }
format.json { render :show, status: :ok, location: #post }
else
format.html { render :edit }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.json
def destroy
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url, notice: 'Post was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
#post = Post.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def post_params
params.require(:post).permit(:user_id, :title, :description, :image, :push, :push_updated_at, ingredients_attributes: [:id, :name, :_destroy])
end
def owned_post
unless current_user == #post.user
flash[:alert] = "That post doesn't belong to you!"
redirect_to root_path
end
end
end
views/posts/index :
<div class="title text-center">
<h1>Alors ? On mange quoi ?</h1>
</div>
<br>
<%= render 'map' %>
<%= render 'post' %>
& views/posts/map :
<script src="//maps.google.com/maps/api/js?v=3.18&sensor=false&client=&key=&libraries=geometry&language=&hl=&region="></script>
<script src="//google-maps-utility-library-v3.googlecode.com/svn/tags/markerclustererplus/2.0.14/src/markerclusterer_packed.js"></script>
<script src='//google-maps-utility-library-v3.googlecode.com/svn/tags/infobox/1.1.9/src/infobox_packed.js' type='text/javascript'></script> <!-- only if you need custom infoboxes -->
<div style='width: 800px;'>
<div id="map" style='width: 800px; height: 400px;'></div>
<script type="text/javascript">
handler = Gmaps.build('Google');
handler.buildMap({ provider: {}, internal: {id: 'map'}}, function(){
markers = handler.addMarkers(<%=raw #hash.to_json %>);
handler.bounds.extendWith(markers);
handler.fitMapToBounds();
});
</script>
</div>
</div>
So if you have any suggestions about that, you're welcome !!
For this stage you should create a scope on model Post
class Post < ActiveRecord::Base
scope :push, ->{ where(push: true).order("push_updated_at DESC") }
end
and then in controller
def index
#posts = Post.push #this will fetch the post with push true and sort it
#hash = Gmaps4rails.build_markers(#posts) do |post, marker|
#rest of your code
end

AJAX not rendering update prior to manual page refresh

I'm working through Agile Web Development with Rails 4, stuck on Chapter 11, Iteration F4. The goal of the section is to have a shopping cart div display only when there are items in the cart, otherwise hide it via display: none. The cart does properly hide itself when the Empty Cart button is clicked, but when an item is then added to it, the cart doesn't display unless the page is then manually refreshed.
Here's what the server output looks like when an item is added to an empty cart:
Started POST "/line_items?product_id=2" for ::1 at 2015-05-10 18:51:44 -0700
Processing by LineItemsController#create as JS
Parameters: {"authenticity_token"=>"v2zcRr2CPsfZP3/qI8l5m0HWdDoOiiyl5oiZxvpYKXp7K2ecXizzCZA37DLm7PwYuSAgemogwjjnDHz4NbavGA==", "product_id"=>"2"}
Cart Load (0.2ms) SELECT "carts".* FROM "carts" WHERE "carts"."id" = ? LIMIT 1 [["id", 21]]
Product Load (0.1ms) SELECT "products".* FROM "products" WHERE "products"."id" = ? LIMIT 1 [["id", 2]]
LineItem Load (0.1ms) SELECT "line_items".* FROM "line_items" WHERE "line_items"."cart_id" = ? AND "line_items"."product_id" = ? LIMIT 1 [["cart_id", 21], ["product_id", 2]]
(0.1ms) begin transaction
SQL (0.4ms) INSERT INTO "line_items" ("product_id", "cart_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["product_id", 2], ["cart_id", 21], ["created_at", "2015-05-11 01:51:44.341300"], ["updated_at", "2015-05-11 01:51:44.341300"]]
(1.1ms) commit transaction
LineItem Load (0.2ms) SELECT "line_items".* FROM "line_items" WHERE "line_items"."cart_id" = ? [["cart_id", 21]]
Product Load (0.2ms) SELECT "products".* FROM "products" WHERE "products"."id" = ? LIMIT 1 [["id", 2]]
Rendered line_items/_line_item.html.erb (2.0ms)
Rendered carts/_cart.html.erb (6.7ms)
Rendered line_items/create.js.erb (8.9ms)
And here's what the output looks like when I refresh:
Started GET "/" for ::1 at 2015-05-10 18:57:17 -0700
Processing by StoreController#index as HTML
Cart Load (0.1ms) SELECT "carts".* FROM "carts" WHERE "carts"."id" = ? LIMIT 1 [["id", 21]]
Product Load (2.2ms) SELECT "products".* FROM "products" ORDER BY "products"."updated_at" DESC LIMIT 1
Product Load (0.2ms) SELECT "products".* FROM "products" ORDER BY "products"."title" ASC
Rendered store/index.html.erb within layouts/application (17.9ms)
LineItem Exists (0.2ms) SELECT 1 AS one FROM "line_items" WHERE "line_items"."cart_id" = ? LIMIT 1 [["cart_id", 21]]
LineItem Load (0.2ms) SELECT "line_items".* FROM "line_items" WHERE "line_items"."cart_id" = ? [["cart_id", 21]]
Product Load (0.1ms) SELECT "products".* FROM "products" WHERE "products"."id" = ? LIMIT 1 [["id", 2]]
Rendered line_items/_line_item.html.erb (1.6ms)
Rendered carts/_cart.html.erb (6.2ms)
Completed 200 OK in 129ms (Views: 124.7ms | ActiveRecord: 3.0ms)
Here's my LineItemsController, containing the create action triggered when I add the item to the empty cart:
class LineItemsController < ApplicationController
include CurrentCart
before_action :set_cart, only: [:create]
before_action :set_line_item, only: [:show, :edit, :update, :destroy]
# GET /line_items
# GET /line_items.json
def index
#line_items = LineItem.all
end
# GET /line_items/1
# GET /line_items/1.json
def show
end
# GET /line_items/new
def new
#line_item = LineItem.new
end
# GET /line_items/1/edit
def edit
end
# POST /line_items
# POST /line_items.json
def create
product = Product.find(params[:product_id])
#line_item = #cart.add_product(product.id)
respond_to do |format|
if #line_item.save
format.html { redirect_to store_url }
format.js { #current_item = #line_item }
format.json { render action: 'show', status: :created, location: #line_item }
else
format.html { render action: 'new' }
format.json { render json: #line_item.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /line_items/1
# PATCH/PUT /line_items/1.json
def update
respond_to do |format|
if #line_item.update(line_item_params)
format.html { redirect_to #line_item, notice: 'Line item was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #line_item.errors, status: :unprocessable_entity }
end
end
end
# DELETE /line_items/1
# DELETE /line_items/1.json
def destroy
#line_item.destroy
respond_to do |format|
format.html { redirect_to line_items_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_line_item
#line_item = LineItem.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def line_item_params
params.require(:line_item).permit(:product_id)
end
end
And this is my StoreController, containing the index action triggered by the manual refresh:
class StoreController < ApplicationController
include CurrentCart
before_action :set_cart
def index
#products = Product.order(:title)
end
end
It seems that when I empty the cart and inspect the div, the display: none attribute is applied (as it should be) from application.html.erb:
<!DOCTYPE html>
<html>
<head>
<title>Pragprog Books Online Store</title>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
</head>
<body class='<%= controller.controller_name %>'>
<div id="banner">
<%= image_tag("logo.png") %>
<%= #page_title || "Pragmatic Bookshelf" %>
</div>
<div id="columns">
<div id="side">
<%= hidden_div_if(#cart.line_items.empty?, id: 'cart') do %>
<%= render #cart %>
<% end %>
<ul>
<li>Home</li>
<li>Questions</li>
<li>News</li>
<li>Contact</li>
</ul>
</div>
<div id="main">
<%= yield %>
</div>
</div>
</body>
</html>
The hidden_div_if method is in ApplicationHelper.rb:
module ApplicationHelper
def hidden_div_if(condition, attributes = {}, &block)
if condition
attributes["style"] = "display: none"
end
content_tag("div", attributes, &block)
end
end
But when I inspect the cart div after adding an item, display: none is still applied. What am I missing?
If it matters, here's my CartsController:
class CartsController < ApplicationController
before_action :set_cart, only: [:show, :edit, :update, :destroy]
rescue_from ActiveRecord::RecordNotFound, with: :invalid_cart
# GET /carts
# GET /carts.json
def index
#carts = Cart.all
end
# GET /carts/1
# GET /carts/1.json
def show
end
# GET /carts/new
def new
#cart = Cart.new
end
# GET /carts/1/edit
def edit
end
# POST /carts
# POST /carts.json
def create
#cart = Cart.new(cart_params)
respond_to do |format|
if #cart.save
format.html { redirect_to #cart, notice: 'Cart was successfully created.' }
format.json { render :show, status: :created, location: #cart }
else
format.html { render :new }
format.json { render json: #cart.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /carts/1
# PATCH/PUT /carts/1.json
def update
respond_to do |format|
if #cart.update(cart_params)
format.html { redirect_to #cart, notice: 'Cart was successfully updated.' }
format.json { render :show, status: :ok, location: #cart }
else
format.html { render :edit }
format.json { render json: #cart.errors, status: :unprocessable_entity }
end
end
end
# DELETE /carts/1
# DELETE /carts/1.json
def destroy
#cart.destroy if #cart.id == session[:cart_id]
session[:cart_id] = nil
respond_to do |format|
format.html { redirect_to store_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_cart
#cart = Cart.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def cart_params
params[:cart]
end
def invalid_cart
logger.error "Attempt to access invalid cart #{params[:id]}"
redirect_to store_url, notice: 'Invalid cart'
end
end
After a couple of days of spinning my wheels, I finally noticed that the jQuery selectors in my create.js.erb were missing the #, i.e.:
if ($('cart tr').length == 1) {
$('cart').show('blind', 1000);
}
Instead of:
if ($('#cart tr').length == 1) {
$('#cart').show('blind', 1000);
}
Adding them fixed it.

Rails 4 Ajax rendering partial multiple times on same page each time submit is hit

Every time I hit submit in my rails app it sends the request 2x. I can get rid of the second partial by hitting refresh. This is a nested app. Todo has_many Items. I included the controllers and the create and the partials.
I included a photo to make a bit more clear.
create.js.erb
$('.todo-items').prepend("<%= escape_javascript(render(#item)) %>");
Items Controller:
class ItemsController < ApplicationController
before_action :set_item, only: [:show, :edit, :update, :destroy]
before_action :set_todo
respond_to :html, :js
# GET /items
# GET /items.json
def index
#items = Item.all
end
# GET /items/1
# GET /items/1.json
def show
#item = Item.find(params[:id])
end
# GET /items/new
def new
#item = #todo.items.build
end
# GET /items/1/edit
def edit
#item = Items.find(params[:id])
end
# POST /items
# POST /items.json
def create
#item = #todo.items.build(item_params)
respond_with(#item) do |format|
if #item.save
format.html { redirect_to [#todo], notice: 'Item was successfully created.' }
format.json { render :show, status: :created, location: #item }
else
format.html { render :new }
format.json { render json: #item.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /items/1
# PATCH/PUT /items/1.json
def update
#item = Item.find(params[:id])
respond_to do |format|
if #item.update(item_params)
format.html { redirect_to [#todo, #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
# DELETE /items/1
# DELETE /items/1.json
def destroy
#item = Item.find(params[:id])
#item.destroy
respond_to do |format|
format.html { redirect_to items_path }
format.json { head :no_content }
format.js { render layout: false }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_item
#item = Item.find(params[:id])
end
def set_todo
#todo = Todo.find(params[:todo_id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def item_params
params.require(:item).permit(:content, :todo_id)
end
end
Todos Controller
class TodosController < ApplicationController
respond_to :html, :js
before_action :set_todo, only: [:show, :edit, :update, :destroy]
# GET /todos
# GET /todos.json
def index
#todos = Todo.all
#todo = Todo.new
end
# GET /todos/1
# GET /todos/1.json
def show
#todo= Todo.find(params[:id])
end
# GET /todos/new
def new
#todo = Todo.new
#3.times{#todo.items.build}
end
# GET /todos/1/edit
def edit
end
# POST /todos
# POST /todos.json
def create
#todo = Todo.new(todo_params)
##todo.items.build
respond_to do |format|
if #todo.save
format.html { redirect_to todo_path, notice: 'Todo was successfully created.' }
format.json { render :show, status: :created, location: #todo }
else
format.html { render :new }
format.json { render json: #todo.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /todos/1
# PATCH/PUT /todos/1.json
def update
#todo = Todo.find(params[:id])
respond_to do |format|
if #todo.update(todo_params)
format.html { redirect_to todos_url, notice: 'Todo was successfully updated.' }
format.json { render :show, status: :ok, location: #todo }
else
format.html { render :edit }
format.json { render json: #todo.errors, status: :unprocessable_entity }
end
end
end
# DELETE /todos/1
# DELETE /todos/1.json
def destroy
#todo.destroy
#todo.items.destroy
respond_to do |format|
format.html { redirect_to todos_url, notice: 'Todo was successfully destroyed.' }
format.json { head :no_content }
end
end
def todo_completed
#todo = Todo.find(params[:id])
#todo.completed = true
if #todo.save
flash[:notice] = "Task was completed."
else
flash[:error] = "There was an error completing the task."
end
#redirect_to tasks_path
respond_with(#todo) do |f|
f.html { redirect_to todos_path }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_todo
#todo = Todo.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def todo_params
params.require(:todo).permit(:title, :completed, items_attributes: [:content,:completed, :_destroy])
end
end
This is the show page the one in the photo for Todo. It is rendering the items underneath that specific todo.
<p>Here are all the things you need to complete</p>
<div class="todo-items">
<%= render partial: 'items/item' %>
</div>
<br>
<div class='new-item'>
<%= render 'items/form'%>
</div>
<%= link_to 'Back', todos_path %>
Items/item
<p>todo/show this is the partial <%= #todo.title %></p>
<table class='table table-bordered'>
<thead>
<tr>
<th>Description</th>
<th> Time Left </th>
<th> Mark Complete </th>
</tr>
</thead>
<tbody>
<% #todo.items.each do |item| %>
<tr>
<td><%= link_to item.content, [#todo, item] %></td>
<td><%= item.days_left %>
<td>
<%= link_to todo_item_path(#todo,item), method: :delete, data: { confirm: 'Are you sure?' }, remote: true, class: 'delete_item' do %>
<i class="fa fa-check"></i>
<% end %>
</td>
</tr>
<% end %>
</tbody>
</table>
<br>
<p>end of partial item</p>
Item/form
<p>
<strong>Todo:</strong>
<%= #todo.title %>
</p>
<%= form_for [#todo, #todo.items.build], remote: true do |f| %>
<div class="field">
<%= f.label :content %><br>
<%= f.text_field :content %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
A little more info from the console. It starts when I click on the list(Groceries) and end with me hitting submit to add the item
Started GET "/todos/25" for 127.0.0.1 at 2014-10-08 19:19:58 -0500
Processing by TodosController#show as HTML
Parameters: {"id"=>"25"}
Todo Load (0.3ms) SELECT "todos".* FROM "todos" WHERE "todos"."id" = ? LIMIT 1 [["id", 25]]
CACHE (0.0ms) SELECT "todos".* FROM "todos" WHERE "todos"."id" = ? LIMIT 1 [["id", "25"]]
Item Load (0.4ms) SELECT "items".* FROM "items" WHERE "items"."todo_id" = ? [["todo_id", 25]]
Rendered items/_item.html.erb (42.9ms)
Rendered items/_form.html.erb (17.3ms)
Rendered todos/show.html.erb within layouts/application (66.6ms)
Completed 200 OK in 346ms (Views: 339.5ms | ActiveRecord: 1.3ms)
Started POST "/todos/25/items" for 127.0.0.1 at 2014-10-08 19:20:12 -0500
Processing by ItemsController#create as JS
Parameters: {"utf8"=>"✓", "item"=>{"content"=>"Cereal"}, "commit"=>"Create Item", "todo_id"=>"25"}
Todo Load (0.2ms) SELECT "todos".* FROM "todos" WHERE "todos"."id" = ? LIMIT 1 [["id", 25]]
(0.3ms) begin transaction
Todo Load (0.2ms) SELECT "todos".* FROM "todos" WHERE "todos"."id" = ? LIMIT 1 [["id", 25]]
SQL (0.5ms) INSERT INTO "items" ("content", "created_at", "todo_id", "updated_at") VALUES (?, ?, ?, ?) [["content", "Cereal"], ["created_at", "2014-10-09 00:20:12.060569"], ["todo_id", 25], ["updated_at", "2014-10-09 00:20:12.060569"]]
(148.1ms) commit transaction
Item Load (0.2ms) SELECT "items".* FROM "items" WHERE "items"."todo_id" = ? [["todo_id", 25]]
Rendered items/_item.html.erb (9.8ms)
Rendered items/create.js.erb (12.5ms)
Completed 200 OK in 180ms (Views: 15.2ms | ActiveRecord: 149.4ms)
The problem is with your create.js.erb file. You have below code:
$('.todo-items').prepend("<%= escape_javascript(render(#item)) %>");
In this code you are pre-pending html in todo-items you should replace items each time instead. like below :
$('.todo-items').html("<%= escape_javascript(render(#item)) %>");
This will replace html each time with new html.

Agile Web Development with Rails: Two (2) items added to depot cart instead of one (1)

So I worked through the Agile Web Development with Rails book, and had a nice functional web application running on Heroku based on the "Depot" app in the book. I was editing CSS/SASS primarily, and I did something that messed up my line_item quantity in my cart.
For the life of me I can't figure out what I've done. Now when I click "Add to cart" button on my main page, 2 items are added to my cart. Does this have something to do with my database? I'm totally flummoxed after losing a bit of my flow in photoshop/CSS-land.
So in a nutshell:
I hit the "Add to cart" button, and I get two of each item I click on.
Here is my carts controller:
class CartsController < ApplicationController
skip_before_filter :authorize, only: [:create, :update, :destroy]
# GET /carts
# GET /carts.json
def index
#carts = Cart.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #carts }
end
end
# GET /carts/1
# GET /carts/1.json
def show
begin
#cart = Cart.find(params[:id])
rescue ActiveRecord::RecordNotFound
logger.error "Attempt to access invalid cart #{params[:id]}"
redirect_to store_url, notice: 'Invalid cart'
else
respond_to do |format|
format.html #show.html.erb
format.json { render json: #cart }
end
end
end
# GET /carts/new
# GET /carts/new.json
def new
#cart = Cart.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #cart }
end
end
# GET /carts/1/edit
def edit
#cart = Cart.find(params[:id])
end
# POST /carts
# POST /carts.json
def create
#cart = Cart.new(params[:cart])
respond_to do |format|
if #cart.save
format.html { redirect_to #cart, notice: 'Cart was successfully created.' }
format.json { render json: #cart, status: :created, location: #cart }
else
format.html { render action: "new" }
format.json { render json: #cart.errors, status: :unprocessable_entity }
end
end
end
# PUT /carts/1
# PUT /carts/1.json
def update
#cart = Cart.find(params[:id])
respond_to do |format|
if #cart.update_attributes(params[:cart])
format.html { redirect_to #cart, notice: 'Cart was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #cart.errors, status: :unprocessable_entity }
end
end
end
# DELETE /carts/1
# DELETE /carts/1.json
def destroy
#cart = current_cart
#cart.destroy
session[:cart_id] = nil
respond_to do |format|
format.html { redirect_to store_url }
format.json { head :no_content }
end
end
end
Here is my models/cart.rb file:
class Cart < ActiveRecord::Base
attr_accessible :title, :body, :name, :quantities_attributes, :quantities, :quantity, :product_id, :line_items
#the addition of everything in attr_accessible after :body may be unnecessary if bugs show up later on...
has_many :line_items, dependent: :destroy
def add_product(product_id)
current_item = line_items.find_by_product_id(product_id)
if current_item
current_item.quantity += 1
else
current_item = line_items.build(product_id: product_id)
end
current_item
end
def total_price
line_items.to_a.sum { |item| item.total_price }
end
end
Here is my create.js.erb file
$("#notice").hide();
if ($('#cart tr').length == 1) { $('#cart').show('blind', 1000); }
$('#cart').html("<%=j render #cart %>");
$('#current_item').css({'background-color':'#fb0f19'}).
animate({'background-color':'#08BBD1'}, 1000);
Here is my application_controller.rb:
class ApplicationController < ActionController::Base
before_filter :authorize
protect_from_forgery
private
def current_cart
Cart.find(session[:cart_id])
rescue ActiveRecord::RecordNotFound
cart = Cart.create
session[:cart_id] = cart.id
cart
end
protected
def authorize
unless User.find_by_id(session[:user_id])
redirect_to login_url, notice: "Please log in"
end
end
end
Here is my views/carts/_cart.html.erb
<% unless cart.line_items.empty? %>
<div class="cart_title">Your Comic Cart</div>
<table>
<%= render(cart.line_items) %>
<tr class="total_line">
<td colspan="2">Total</td>
<td class="total_cell"><%= cart.total_price %> BTC</td>
</tr>
</table>
<%= button_to "Checkout", new_order_path, method: :get %>
<%= button_to 'Empty cart', cart, method: :delete,
confirm: 'Are you sure?' %>
<% end %>
line_items_controller.rb:
class LineItemsController < ApplicationController
skip_before_filter :authorize, only: :create
# GET /line_items
# GET /line_items.json
def index
#line_items = LineItem.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #line_items }
end
end
# GET /line_items/1
# GET /line_items/1.json
def show
#line_item = LineItem.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #line_item }
end
end
# GET /line_items/new
# GET /line_items/new.json
def new
#line_item = LineItem.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #line_item }
end
end
# GET /line_items/1/edit
def edit
#line_item = LineItem.find(params[:id])
end
# POST /line_items
# POST /line_items.json
def create
#cart = current_cart
product = Product.find(params[:product_id])
#line_item = #cart.add_product(product.id)
respond_to do |format|
if #line_item.save
format.html { redirect_to store_url }
format.js { #current_item = #line_item }
format.json { render json: #line_item,
status: :created, location: #line_item }
else
format.html { render action: "new" }
format.json { render json: #line_item.errors, status: :unprocessable_entity }
end
end
end
# PUT /line_items/1
# PUT /line_items/1.json
def update
#line_item = LineItem.find(params[:id])
respond_to do |format|
if #line_item.update_attributes(params[:line_item])
format.html { redirect_to #line_item, notice: 'Line item was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #line_item.errors, status: :unprocessable_entity }
end
end
end
# DELETE /line_items/1
# DELETE /line_items/1.json
def destroy
#line_item = LineItem.find(params[:id])
#line_item.destroy
respond_to do |format|
format.html { redirect_to line_items_url }
format.json { head :no_content }
end
end
end
I'm not sure if there are more files worth showing, it is late and I'm super lost, so I probably should have waited until morning to post this. Let me know if anyone else has run into this. I still have a hard time with databases, so I could be completely missing the right place to be looking. Thanks for any help, I know this misstep lacks focus in my explination.
I think the problem is in your store.js.coffee. Check and modify the code as per errata 153 from below link:
http://pragprog.com/titles/rails4/errata
i.e change $(document).on "ready page:change" to $(document).on "ready, page:change"

Categories

Resources