Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Almost green: room_id is undefined in cucumber for some reason

  • Loading branch information...
commit 494d04cb23bdefdf84b62adaad90f60b402800ea 1 parent 97c6db1
@jasonm authored
View
2  Guardfile
@@ -10,4 +10,6 @@ guard 'spork', :cucumber_env => { 'RAILS_ENV' => 'test' }, :rspec_env => { 'RAIL
watch('Gemfile')
watch('Gemfile.lock')
watch('spec/spec_helper.rb')
+ watch('spec/factories.rb')
+ watch(%r{^spec/factories/.+\.rb$})
end
View
2  README.md
@@ -12,7 +12,7 @@ You can login with any name, it's stored in the session. User.find_or_create_by
User: [id, name]
Room: [id, name]
-Message: [id, user_id, body]
+Message: [id, user_id, room_id, body]
Features:
View
4 app/assets/javascripts/backbone/collections/messages.js
@@ -0,0 +1,4 @@
+window.ChatApp.Collections.Messages = Backbone.Collection.extend({
+ url: '/messages',
+ model: ChatApp.Models.Message
+});
View
3  app/assets/javascripts/backbone/collections/rooms.js
@@ -1,3 +1,4 @@
window.ChatApp.Collections.Rooms = Backbone.Collection.extend({
- url: '/rooms'
+ url: '/rooms',
+ model: ChatApp.Models.Room
});
View
2  app/assets/javascripts/backbone/models/message.js
@@ -0,0 +1,2 @@
+window.ChatApp.Models.Message = Backbone.Model.extend({
+});
View
4 app/assets/javascripts/backbone/models/room.js
@@ -1,2 +1,6 @@
window.ChatApp.Models.Room = Backbone.Model.extend({
+ initialize: function() {
+ this.messages = new ChatApp.Collections.Messages();
+ this.messages.url = '/rooms/' + this.id + '/messages';
+ }
});
View
35 app/assets/javascripts/backbone/views/room.js
@@ -1,11 +1,46 @@
window.ChatApp.Views.Room = Backbone.View.extend({
initialize: function() {
+ this.rendered = new $.Deferred();
+
+ _.bindAll(this, "submit", "renderMessages");
+
+ this.messages = this.model.messages;
+ this.messages.bind("add", this.renderMessages);
+ this.messages.fetch({ success: this.renderMessages });
+ },
+
+ events: {
+ "submit form": "submit"
},
template: JST['room'],
render: function() {
$(this.el).empty().append(this.template({ room: this.model }));
+ this.rendered.resolve();
return this;
+ },
+
+ renderMessages: function() {
+ var self = this;
+ this.rendered.done(function() {
+ var ul = self.$("ul#chat-messages");
+ var messageTemplate = JST['message'];
+
+ ul.empty();
+ self.messages.each(function(message) {
+ ul.append(messageTemplate({ message: message }));
+ });
+ });
+ },
+
+ submit: function(event) {
+ event.preventDefault();
+
+ this.messages.create({
+ body: this.$("input[name=body]").val()
+ });
+
+ this.$("input[name=body]").val("");
}
});
View
1  app/assets/templates/message.jst.ejs
@@ -0,0 +1 @@
+<li><%= message.escape('user_name') %>: <%= message.escape('body') %></li>
View
15 app/assets/templates/room.jst.ejs
@@ -0,0 +1,15 @@
+<h3><%= room.escape('name') %></h3>
+<ul id="chat-messages">
+</ul>
+
+<form id="new-chat-message">
+ <fieldset class="inputs">
+ <ol>
+ <li>
+ <label for="new-message-name">Chat</label>
+ <input type="text" name="body" id="new-message-name">
+ <input name="commit" type="submit" value="Send">
+ </li>
+ </ol>
+ </fieldset>
+</form>
View
2  app/assets/templates/room_list_item.jst.ejs
@@ -1 +1 @@
-<li><a href="#rooms/<%= room.get('id') %>"><%= room.get('name') %></a></li>
+<li><a href="#rooms/<%= room.get('id') %>"><%= room.escape('name') %></a></li>
View
15 app/controllers/messages_controller.rb
@@ -0,0 +1,15 @@
+class MessagesController < ApplicationController
+ respond_to :json, only: [:index, :create]
+
+ def index
+ room = Room.find(params[:room_id])
+ render json: room.messages
+ end
+
+ def create
+ room = Room.find(params[:room_id])
+ message = room.messages.create(params[:message].merge(user_id: current_user.id))
+ render json: message
+ end
+end
+
View
14 app/models/message.rb
@@ -0,0 +1,14 @@
+class Message < ActiveRecord::Base
+ belongs_to :room
+ belongs_to :user
+
+ validates :body, presence: true
+
+ def as_json(options={})
+ super(methods: [:user_name])
+ end
+
+ def user_name
+ user.name
+ end
+end
View
1  app/models/room.rb
@@ -1,2 +1,3 @@
class Room < ActiveRecord::Base
+ has_many :messages
end
View
4 config/routes.rb
@@ -6,7 +6,9 @@
match 'logout' => 'sessions#destroy'
resource :chat, only: %w(show)
- resources :rooms, only: %w(create)
+ resources :rooms, only: %w(create) do
+ resources :messages, only: %w(index create)
+ end
if %w(development test).include? Rails.env
mount Jasminerice::Engine => "/jasmine"
View
11 db/migrate/20111011015912_create_messages.rb
@@ -0,0 +1,11 @@
+class CreateMessages < ActiveRecord::Migration
+ def change
+ create_table :messages do |t|
+ t.integer :user_id
+ t.integer :room_id
+ t.text :body
+
+ t.timestamps
+ end
+ end
+end
View
2  features/step_definitions/chat_steps.rb
@@ -3,7 +3,7 @@
end
Then /^I should see an empty chat$/ do
- page.should have_no_css(selector_for('chat room messages'))
+ page.should have_no_css(selector_for('a chat room message'))
end
When /^I say "([^"]*)"$/ do |message|
View
2  features/support/selectors.rb
@@ -18,6 +18,8 @@ def selector_for(locator)
"ul#chat-rooms>li>a"
when "chat room messages"
"ul#chat-messages>li"
+ when "a chat room message"
+ "ul#chat-messages>li"
# Add more mappings here.
# Here is an example that pulls values out of the Regexp:
View
10 spec/factories.rb
@@ -4,4 +4,14 @@
name "User #{n}"
end
end
+
+ factory :room do
+ name "A chat room"
+ end
+
+ factory :message do
+ body "Body"
+ user
+ room
+ end
end
View
9 spec/javascripts/collections/messages_spec.js
@@ -0,0 +1,9 @@
+describe("ChatApp.Collections.Messages", function() {
+ it("has a url of /messages", function() {
+ expect(new ChatApp.Collections.Messages().url).toEqual("/messages");
+ });
+
+ it("holds instances of ChatApp.Models.Message", function() {
+ expect(new ChatApp.Collections.Messages().model).toEqual(ChatApp.Models.Message);
+ });
+});
View
4 spec/javascripts/collections/rooms_spec.js
@@ -2,4 +2,8 @@ describe("Collections.Rooms", function() {
it("has a url of /rooms", function() {
expect(new ChatApp.Collections.Rooms().url).toEqual("/rooms");
});
+
+ it("holds instances of ChatApp.Models.Room", function() {
+ expect(new ChatApp.Collections.Rooms().model).toEqual(ChatApp.Models.Room);
+ });
});
View
5 spec/javascripts/models/room_spec.js
@@ -1,2 +1,7 @@
describe("Models.Room", function() {
+ it("nests messages", function() {
+ var room = new ChatApp.Models.Room({ id: 15 });
+ expect(room.messages instanceof ChatApp.Collections.Messages).toBeTruthy();
+ expect(room.messages.url).toEqual("/rooms/15/messages");
+ });
});
View
48 spec/javascripts/views/room_spec.js
@@ -1,2 +1,50 @@
describe("ChatApp.Views.Room", function() {
+ var users, messages, room, el, view;
+
+ beforeEach(function() {
+ messages = new ChatApp.Collections.Messages([{ body: "Hello", user_name: "Jason" }]);
+
+ sinon.stub(messages, "fetch", function(options) {
+ options.success();
+ });
+
+ room = new ChatApp.Models.Room({ name: "Red", id: 1 });
+ room.messages = messages;
+
+ el = $("<div></div>");
+ view = new ChatApp.Views.Room({ el: el, model: room });
+ });
+
+ it("renders a new message form", function() {
+ view.render();
+
+ expect(el).toContain("form");
+ expect(el).toContain("form input[type=text][name=body]");
+ expect(el).toContain("form input[type=submit]");
+ });
+
+ it("creates a new message when the form is submitted", function() {
+ sinon.stub(messages, "create");
+ view.render();
+
+ $("input[name=body]", el).val("Hello");
+ $("form", el).submit();
+
+ expect(messages.create).toHaveBeenCalledWith({ body: "Hello" });
+ expect($("input[name=body]", el).val()).toEqual("");
+ });
+
+ it("fetches and renders messages", function() {
+ view.render();
+
+ expect(messages.fetch).toHaveBeenCalled();
+ expect(el).toContain("ul#chat-messages li:contains('Jason: Hello')");
+ });
+
+ it("re-renders when messages are added", function() {
+ view.render();
+
+ messages.add([{ body: "Goodbye", user_name: "Jason" }]);
+ expect(el).toContain("ul#chat-messages li:contains('Jason: Goodbye')");
+ });
});
View
12 spec/models/message_spec.rb
@@ -0,0 +1,12 @@
+require 'spec_helper'
+
+describe Message do
+ it { should belong_to :room }
+ it { should belong_to :user }
+ it { should validate_presence_of :body }
+
+ it "includes user name in JSON" do
+ message = Factory(:message, user: Factory(:user, name: "Jason"))
+ message.as_json[:user_name].should == "Jason"
+ end
+end
View
1  spec/models/room_spec.rb
@@ -1,4 +1,5 @@
require 'spec_helper'
describe Room do
+ it { should have_many :messages }
end
Please sign in to comment.
Something went wrong with that request. Please try again.