From 540af5c8954cebdb1705a99a8624ab03d59aff5c Mon Sep 17 00:00:00 2001 From: danirubio Date: Tue, 27 Mar 2012 19:53:48 +0200 Subject: [PATCH 01/21] anadir accion ejemplo --- Gemfile.lock | 2 ++ app/controllers/planet_controller.rb | 5 +++++ config/routes.rb | 2 ++ 3 files changed, 9 insertions(+) diff --git a/Gemfile.lock b/Gemfile.lock index 81a3ba7..0ff18c7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -89,6 +89,7 @@ GEM rack (~> 1.0) tilt (~> 1.1, != 1.3.0) sqlite3 (1.3.5) + sqlite3 (1.3.5-x86-mingw32) thor (0.14.6) tilt (1.3.3) treetop (1.4.10) @@ -101,6 +102,7 @@ GEM PLATFORMS ruby + x86-mingw32 DEPENDENCIES coffee-rails (~> 3.2.1) diff --git a/app/controllers/planet_controller.rb b/app/controllers/planet_controller.rb index be7ac0a..3b30d6f 100644 --- a/app/controllers/planet_controller.rb +++ b/app/controllers/planet_controller.rb @@ -7,5 +7,10 @@ def contact def ejemplo end + + # GET /planet/author + def author + + end end diff --git a/config/routes.rb b/config/routes.rb index 4cd1976..4f34f88 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -7,6 +7,8 @@ get "planet/ejemplo" + get "planet/author" # se añande una nueva ruta a la acción "author" + # The priority is based upon order of creation: # first created -> highest priority. From 5a29c6b08a281f55d45e6f0c7e840415628f0020 Mon Sep 17 00:00:00 2001 From: danirubio Date: Wed, 28 Mar 2012 16:12:31 +0200 Subject: [PATCH 02/21] creacion author y test de funcionalidad --- app/assets/images/danielrubio.jpg | Bin 0 -> 219854 bytes app/assets/images/juanquemada.jpg | Bin 0 -> 2211 bytes app/assets/images/juanquemada2.jpg | Bin 0 -> 37081 bytes app/views/planet/author.html.erb | 29 +++++++++++++ exi | 47 ++++++++++++++++++++++ lessecho.exe.stackdump | 8 ++++ test/functional/planet_controller_test.rb | 12 ++++++ 7 files changed, 96 insertions(+) create mode 100644 app/assets/images/danielrubio.jpg create mode 100644 app/assets/images/juanquemada.jpg create mode 100644 app/assets/images/juanquemada2.jpg create mode 100644 app/views/planet/author.html.erb create mode 100644 exi create mode 100644 lessecho.exe.stackdump diff --git a/app/assets/images/danielrubio.jpg b/app/assets/images/danielrubio.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cf037cbdeb918eef405512f25fb082601fc436d7 GIT binary patch literal 219854 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 C;;1PA literal 0 HcmV?d00001 diff --git a/app/assets/images/juanquemada.jpg b/app/assets/images/juanquemada.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2dceac4f06c5485fc97e22c5f1daf80ea741a25a GIT binary patch literal 2211 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 IPdj6O0A0M~)Bpeg literal 0 HcmV?d00001 diff --git a/app/assets/images/juanquemada2.jpg b/app/assets/images/juanquemada2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..df19bf0d542ffeac31ddcc8d7ece35240a8c32df GIT binary patch literal 37081 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 literal 0 HcmV?d00001 diff --git a/app/views/planet/author.html.erb b/app/views/planet/author.html.erb new file mode 100644 index 0000000..c8cce66 --- /dev/null +++ b/app/views/planet/author.html.erb @@ -0,0 +1,29 @@ +

Bienvenido a la sección de los autores de este website

+ +

Aquí podrá encontrar una breve descripción de los autores principales + de esta página web, así como las formas de contactar con ellos.

+ +

Juan Quemada Vives

+<%= image_tag('juanquemada.jpg')%> + +

Catedrático de Ingeniería Telemática

+ +

Catedrático del Departamento de Ingeniería de Sistemas Telemáticos (DIT) en la ETSI Telecomunicación de la Universidad Politécnica de Madrid (UPM), Investigador Principal del Grupo Internet NG (donde se han desarrollado la aplicación Isabel y el Global Plaza), Director de la Cátedra Telefónica para Internet NG, emprendedor y promotor de Agora Systems SA, representante de UPM en el World Wide Web Consortium, realizó la primera conexión en España a un servicio de Internet (email/EUNET) en 1985 junto con otros compañeros. Su investigación se centra en en el diseño de aplicaciones de colaboración, redes sociales y en TIC en education. Tiene una alta participación en proyectos de investigación europeos y nacionales (FI-WARE, GLOBAL Excursion, GLOBAL, ITECBAN, CEPOS, Ecospace, Collaboration@Rural, iCamp, Euro6IX, etc.). Posee múltiples publicaciones en estas áreas.

+ +

Contacto

+ +

+34 91 3367331, +34 91 3367333
juanquemada@dit.upm.es
+ETSI Telecomunicación (B-202). Avenida Complutense 30, E-28040 Madrid, Spain

+ + +

Daniel Rubio Mesa

+<%= image_tag('danielrubio.jpg') %> + +

Estudiante de Ingeniería Superior de Telecomunicación en ETSIT UPM

+ +

Estudiante de 4º-5º curso en las especialidades de Telemática y Gestión de la Tecnología

+ +

Contacto

+ +

+34 91 0000000
danielrubiomesa@gmail.com
+E-28924 Alcorcón Madrid, Spain

\ No newline at end of file diff --git a/exi b/exi new file mode 100644 index 0000000..45a05fc --- /dev/null +++ b/exi @@ -0,0 +1,47 @@ +commit 540af5c8954cebdb1705a99a8624ab03d59aff5c +Author: danirubio +Date: Tue Mar 27 19:53:48 2012 +0200 + + anadir accion ejemplo + +commit df46232168e8953e41d08d5bbe938466b63d7833 +Author: Juan Quemada +Date: Sun Mar 18 00:28:22 2012 +0100 + + se añade seeds.rb + +commit 4d0b4bbc2de9eccbd0d24b55055c8daa2bd46f9d +Author: Juan Quemada +Date: Sun Mar 18 00:24:48 2012 +0100 + + migración base de datos + +commit 3a7e703449b7610f4f52cb88c2bda5eecf805770 +Author: Juan Quemada +Date: Sun Mar 18 00:16:47 2012 +0100 + + creación de scaffold type + +commit c5aade1b24ba2cf926e0a2e8d051191b20616ccb +Author: Juan Quemada +Date: Sun Mar 18 00:12:51 2012 +0100 + + añadir acción ejemplo + +commit 37df8e02cce7975af25f3ff0ff60360fa4247519 +Author: Juan Quemada +Date: Sun Mar 18 00:06:27 2012 +0100 + + vistas index y contact, y redirección de route + +commit 1e039877cc95c84e7a50db112559835f41fc0c5c +Author: Juan Quemada +Date: Sat Mar 17 23:48:43 2012 +0100 + + rails generate controller planet index contact + +commit b617c7af019dcf8b4d1596c07e59e6d3efcfb439 +Author: Juan Quemada +Date: Sat Mar 17 23:47:06 2012 +0100 + + new planet creado diff --git a/lessecho.exe.stackdump b/lessecho.exe.stackdump new file mode 100644 index 0000000..1af68c6 --- /dev/null +++ b/lessecho.exe.stackdump @@ -0,0 +1,8 @@ +MSYS-1.0.17 Build:2011-04-24 23:39 +Exception: STATUS_ACCESS_VIOLATION at eip=00000000 +eax=685537DC ebx=685538E4 ecx=0001B008 edx=000000E4 esi=00000000 edi=685500D4 +ebp=0028FEC8 esp=0028FEAC program=c:\Ruby193\bin\lessecho.exe +cs=0023 ds=002B es=002B fs=0053 gs=002B ss=002B +Stack trace: +Frame Function Args +End of stack trace \ No newline at end of file diff --git a/test/functional/planet_controller_test.rb b/test/functional/planet_controller_test.rb index 88229e0..d3f9024 100644 --- a/test/functional/planet_controller_test.rb +++ b/test/functional/planet_controller_test.rb @@ -11,4 +11,16 @@ class PlanetControllerTest < ActionController::TestCase assert_response :success end + #test de funcionalidad de GET /planet/ejemplo + test "should get ejemplo" do + get :ejemplo + assert_response :success + end + + #test de funcionalidad de GET /planet/author + test "should get author" do + get :author + assert_response :success + end + end From 9eaf8d49ce8794a3b550979f10a9088a18be82af Mon Sep 17 00:00:00 2001 From: danirubio Date: Wed, 28 Mar 2012 16:34:03 +0200 Subject: [PATCH 03/21] anadido el campo last modified --- app/views/planet/index.html.erb | 2 +- app/views/types/index.html.erb | 2 ++ app/views/types/show.html.erb | 4 ++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/views/planet/index.html.erb b/app/views/planet/index.html.erb index bbee722..9633fdb 100644 --- a/app/views/planet/index.html.erb +++ b/app/views/planet/index.html.erb @@ -1 +1 @@ -

Wecome to the Planet Travel Site

This site gathers information of touristic sites from all over the world and should help you to organize your trips and your holidays.

<%= image_tag('pedriza2-m.png') %>

Feel free to use it for your convenience and pleasure.

\ No newline at end of file +

Welcome to the Planet Travel Site

This site gathers information of touristic sites from all over the world and should help you to organize your trips and your holidays.

<%= image_tag('pedriza2-m.png') %>

Feel free to use it for your convenience and pleasure.

\ No newline at end of file diff --git a/app/views/types/index.html.erb b/app/views/types/index.html.erb index 50bda49..1d2e3ef 100644 --- a/app/views/types/index.html.erb +++ b/app/views/types/index.html.erb @@ -4,6 +4,7 @@ Name Description + Last modified @@ -13,6 +14,7 @@ <%= type.name %> <%= type.description %> + <%= type.updated_at %> <%= link_to 'Show', type %> <%= link_to 'Edit', edit_type_path(type) %> <%= link_to 'Destroy', type, confirm: 'Are you sure?', method: :delete %> diff --git a/app/views/types/show.html.erb b/app/views/types/show.html.erb index 98b32e7..a6b0e8d 100644 --- a/app/views/types/show.html.erb +++ b/app/views/types/show.html.erb @@ -10,6 +10,10 @@ <%= @type.description %>

+

+ Last modified: + <%= @type.updated_at %> +

<%= link_to 'Edit', edit_type_path(@type) %> | <%= link_to 'Back', types_path %> From 67d663e508adb12b20eb99fa7eac3cb89fcc92ed Mon Sep 17 00:00:00 2001 From: danirubio Date: Wed, 28 Mar 2012 21:36:27 +0200 Subject: [PATCH 04/21] anadido ordered_index en types --- app/controllers/planet_controller.rb | 3 +-- app/controllers/types_controller.rb | 13 ++++++++++++- app/views/types/ordered_index.html.erb | 27 ++++++++++++++++++++++++++ config/routes.rb | 4 ++++ 4 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 app/views/types/ordered_index.html.erb diff --git a/app/controllers/planet_controller.rb b/app/controllers/planet_controller.rb index 3b30d6f..759b28a 100644 --- a/app/controllers/planet_controller.rb +++ b/app/controllers/planet_controller.rb @@ -9,8 +9,7 @@ def ejemplo end # GET /planet/author - def author - + def author end end diff --git a/app/controllers/types_controller.rb b/app/controllers/types_controller.rb index da826f4..0b29f48 100644 --- a/app/controllers/types_controller.rb +++ b/app/controllers/types_controller.rb @@ -10,6 +10,17 @@ def index end end + # GET /types/ordered_index + # GET /types/ordered_index.json + def ordered_index + @types = Type.find(:all, :order=>:name) + + respond_to do |format| + format.html #ordered_index.html.erb + format.json { render json: @type } + end + end + # GET /types/1 # GET /types/1.json def show @@ -80,4 +91,4 @@ def destroy format.json { head :no_content } end end -end +end \ No newline at end of file diff --git a/app/views/types/ordered_index.html.erb b/app/views/types/ordered_index.html.erb new file mode 100644 index 0000000..1d2e3ef --- /dev/null +++ b/app/views/types/ordered_index.html.erb @@ -0,0 +1,27 @@ +

Listing types

+ + + + + + + + + + + +<% @types.each do |type| %> + + + + + + + + +<% end %> +
NameDescriptionLast modified
<%= type.name %><%= type.description %><%= type.updated_at %><%= link_to 'Show', type %><%= link_to 'Edit', edit_type_path(type) %><%= link_to 'Destroy', type, confirm: 'Are you sure?', method: :delete %>
+ +
+ +<%= link_to 'New Type', new_type_path %> diff --git a/config/routes.rb b/config/routes.rb index 4f34f88..8b693a3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,7 @@ Planet::Application.routes.draw do + + get "types/ordered_index" # se añade una nueva ruta a la acción "ordered_index" + resources :types get "planet/index" @@ -9,6 +12,7 @@ get "planet/author" # se añande una nueva ruta a la acción "author" + # The priority is based upon order of creation: # first created -> highest priority. From 0309cc5c48b467a0da9461f4578bb313db0dd90c Mon Sep 17 00:00:00 2001 From: danirubio Date: Wed, 28 Mar 2012 21:42:48 +0200 Subject: [PATCH 05/21] anadido test de funcionalidad para ordered_index --- test/functional/types_controller_test.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/functional/types_controller_test.rb b/test/functional/types_controller_test.rb index 2e1931b..a07e4a1 100644 --- a/test/functional/types_controller_test.rb +++ b/test/functional/types_controller_test.rb @@ -11,6 +11,13 @@ class TypesControllerTest < ActionController::TestCase assert_not_nil assigns(:types) end + #test de funcionalidad de GET /types/ordered_index + test "should get ordered_index" do + get :ordered_index + assert_response :success + assert_not_nil assigns(:types) + end + test "should get new" do get :new assert_response :success From 8f78fb7bedcb11ed6d856747943c78e4c69e137f Mon Sep 17 00:00:00 2001 From: danirubio Date: Wed, 28 Mar 2012 22:08:27 +0200 Subject: [PATCH 06/21] anadidos hiperenlaces superiores e inferiores --- app/views/layouts/application.html.erb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 062c0a4..2131fa9 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -7,8 +7,22 @@ <%= csrf_meta_tags %> + <%= link_to "Inicio", planet_index_path %> + <%= link_to "Contacto", planet_contact_path %> + <%= link_to "Ejemplo", planet_ejemplo_path %> + <%= link_to "Autores", planet_author_path %> + <%= link_to "Tipos", types_path %> + <%= link_to "Tipos ordenados", types_ordered_index_path %>
<%= yield %> +
+ <%= link_to "Inicio", planet_index_path %> + <%= link_to "Contacto", planet_contact_path %> + <%= link_to "Ejemplo", planet_ejemplo_path %> + <%= link_to "Autores", planet_author_path %> + <%= link_to "Tipos", types_path %> + <%= link_to "Tipos ordenados", types_ordered_index_path %>
+ From 3a39865b7eb786f827b5992b39193321b0949634 Mon Sep 17 00:00:00 2001 From: danirubio Date: Thu, 29 Mar 2012 12:32:10 +0200 Subject: [PATCH 07/21] version final entrega5 --- app/views/layouts/application.html.erb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 00a5233..fbc0caa 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -25,6 +25,7 @@ <%= link_to "Autores", planet_author_path %> <%= link_to "Tipos", types_path %> <%= link_to "Tipos ordenados", types_ordered_index_path %> + <%= link_to "Sitios", sites_path %>
<%= yield %> @@ -36,6 +37,7 @@ <%= link_to "Autores", planet_author_path %> <%= link_to "Tipos", types_path %> <%= link_to "Tipos ordenados", types_ordered_index_path %> + <%= link_to "Sitios", sites_path %>
\ No newline at end of file From dbc48163fd52d2051cf09b98286945f001e5e5d9 Mon Sep 17 00:00:00 2001 From: danirubio Date: Sun, 15 Apr 2012 19:16:03 +0200 Subject: [PATCH 08/21] instalar devise,user y nombre --- Gemfile | 2 + Gemfile.lock | 11 + app/models/user.rb | 9 + config/initializers/devise.rb | 223 ++++++++++++++++++ config/locales/devise.en.yml | 57 +++++ config/routes.rb | 2 + .../20120415165600_devise_create_users.rb | 49 ++++ db/migrate/20120415170814_user_name.rb | 13 + db/schema.rb | 23 +- test/fixtures/users.yml | 11 + test/unit/user_test.rb | 7 + 11 files changed, 406 insertions(+), 1 deletion(-) create mode 100644 app/models/user.rb create mode 100644 config/initializers/devise.rb create mode 100644 config/locales/devise.en.yml create mode 100644 db/migrate/20120415165600_devise_create_users.rb create mode 100644 db/migrate/20120415170814_user_name.rb create mode 100644 test/fixtures/users.yml create mode 100644 test/unit/user_test.rb diff --git a/Gemfile b/Gemfile index 7764763..7231379 100644 --- a/Gemfile +++ b/Gemfile @@ -7,6 +7,8 @@ gem 'rails', '3.2.2' gem 'sqlite3' +gem 'devise' + # Gems used only for assets and not required # in production environments by default. diff --git a/Gemfile.lock b/Gemfile.lock index 0ff18c7..5730fc3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -29,6 +29,8 @@ GEM i18n (~> 0.6) multi_json (~> 1.0) arel (3.0.2) + bcrypt-ruby (3.0.1) + bcrypt-ruby (3.0.1-x86-mingw32) builder (3.0.0) coffee-rails (3.2.2) coffee-script (>= 2.2.0) @@ -37,6 +39,11 @@ GEM coffee-script-source execjs coffee-script-source (1.2.0) + devise (2.0.4) + bcrypt-ruby (~> 3.0) + orm_adapter (~> 0.0.3) + railties (~> 3.1) + warden (~> 1.1.1) erubis (2.7.0) execjs (1.3.0) multi_json (~> 1.0) @@ -53,6 +60,7 @@ GEM treetop (~> 1.4.8) mime-types (1.17.2) multi_json (1.1.0) + orm_adapter (0.0.7) polyglot (0.3.3) rack (1.4.1) rack-cache (1.2) @@ -99,6 +107,8 @@ GEM uglifier (1.2.3) execjs (>= 0.3.0) multi_json (>= 1.0.2) + warden (1.1.1) + rack (>= 1.0) PLATFORMS ruby @@ -106,6 +116,7 @@ PLATFORMS DEPENDENCIES coffee-rails (~> 3.2.1) + devise jquery-rails rails (= 3.2.2) sass-rails (~> 3.2.3) diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..1591323 --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,9 @@ +class User < ActiveRecord::Base + # Include default devise modules. Others available are: + # :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable + devise :database_authenticatable, :registerable, + :recoverable, :rememberable, :trackable, :validatable + + # Setup accessible (or protected) attributes for your model + attr_accessible :name,:email, :password, :password_confirmation, :remember_me +end diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb new file mode 100644 index 0000000..62146ea --- /dev/null +++ b/config/initializers/devise.rb @@ -0,0 +1,223 @@ +# Use this hook to configure devise mailer, warden hooks and so forth. +# Many of these configuration options can be set straight in your model. +Devise.setup do |config| + # ==> Mailer Configuration + # Configure the e-mail address which will be shown in Devise::Mailer, + # note that it will be overwritten if you use your own mailer class with default "from" parameter. + config.mailer_sender = "please-change-me-at-config-initializers-devise@example.com" + + # Configure the class responsible to send e-mails. + # config.mailer = "Devise::Mailer" + + # Automatically apply schema changes in tableless databases + config.apply_schema = false + + # ==> ORM configuration + # Load and configure the ORM. Supports :active_record (default) and + # :mongoid (bson_ext recommended) by default. Other ORMs may be + # available as additional gems. + require 'devise/orm/active_record' + + # ==> Configuration for any authentication mechanism + # Configure which keys are used when authenticating a user. The default is + # just :email. You can configure it to use [:username, :subdomain], so for + # authenticating a user, both parameters are required. Remember that those + # parameters are used only when authenticating and not when retrieving from + # session. If you need permissions, you should implement that in a before filter. + # You can also supply a hash where the value is a boolean determining whether + # or not authentication should be aborted when the value is not present. + # config.authentication_keys = [ :email ] + + # Configure parameters from the request object used for authentication. Each entry + # given should be a request method and it will automatically be passed to the + # find_for_authentication method and considered in your model lookup. For instance, + # if you set :request_keys to [:subdomain], :subdomain will be used on authentication. + # The same considerations mentioned for authentication_keys also apply to request_keys. + # config.request_keys = [] + + # Configure which authentication keys should be case-insensitive. + # These keys will be downcased upon creating or modifying a user and when used + # to authenticate or find a user. Default is :email. + config.case_insensitive_keys = [ :email ] + + # Configure which authentication keys should have whitespace stripped. + # These keys will have whitespace before and after removed upon creating or + # modifying a user and when used to authenticate or find a user. Default is :email. + config.strip_whitespace_keys = [ :email ] + + # Tell if authentication through request.params is enabled. True by default. + # It can be set to an array that will enable params authentication only for the + # given strategies, for example, `config.params_authenticatable = [:database]` will + # enable it only for database (email + password) authentication. + # config.params_authenticatable = true + + # Tell if authentication through HTTP Basic Auth is enabled. False by default. + # It can be set to an array that will enable http authentication only for the + # given strategies, for example, `config.http_authenticatable = [:token]` will + # enable it only for token authentication. + # config.http_authenticatable = false + + # If http headers should be returned for AJAX requests. True by default. + # config.http_authenticatable_on_xhr = true + + # The realm used in Http Basic Authentication. "Application" by default. + # config.http_authentication_realm = "Application" + + # It will change confirmation, password recovery and other workflows + # to behave the same regardless if the e-mail provided was right or wrong. + # Does not affect registerable. + # config.paranoid = true + + # By default Devise will store the user in session. You can skip storage for + # :http_auth and :token_auth by adding those symbols to the array below. + # Notice that if you are skipping storage for all authentication paths, you + # may want to disable generating routes to Devise's sessions controller by + # passing :skip => :sessions to `devise_for` in your config/routes.rb + config.skip_session_storage = [:http_auth] + + # ==> Configuration for :database_authenticatable + # For bcrypt, this is the cost for hashing the password and defaults to 10. If + # using other encryptors, it sets how many times you want the password re-encrypted. + # + # Limiting the stretches to just one in testing will increase the performance of + # your test suite dramatically. However, it is STRONGLY RECOMMENDED to not use + # a value less than 10 in other environments. + config.stretches = Rails.env.test? ? 1 : 10 + + # Setup a pepper to generate the encrypted password. + # config.pepper = "fc2b132b907808e63a027e4947cc470c1dad8d17f556b9bbc1af44a17a7d026437c11619006bb843ccde92c04161176b3aeee299e21eee60a00b0167594060b6" + + # ==> Configuration for :confirmable + # A period that the user is allowed to access the website even without + # confirming his account. For instance, if set to 2.days, the user will be + # able to access the website for two days without confirming his account, + # access will be blocked just in the third day. Default is 0.days, meaning + # the user cannot access the website without confirming his account. + # config.allow_unconfirmed_access_for = 2.days + + # If true, requires any email changes to be confirmed (exctly the same way as + # initial account confirmation) to be applied. Requires additional unconfirmed_email + # db field (see migrations). Until confirmed new email is stored in + # unconfirmed email column, and copied to email column on successful confirmation. + config.reconfirmable = true + + # Defines which key will be used when confirming an account + # config.confirmation_keys = [ :email ] + + # ==> Configuration for :rememberable + # The time the user will be remembered without asking for credentials again. + # config.remember_for = 2.weeks + + # If true, extends the user's remember period when remembered via cookie. + # config.extend_remember_period = false + + # If true, uses the password salt as remember token. This should be turned + # to false if you are not using database authenticatable. + config.use_salt_as_remember_token = true + + # Options to be passed to the created cookie. For instance, you can set + # :secure => true in order to force SSL only cookies. + # config.cookie_options = {} + + # ==> Configuration for :validatable + # Range for password length. Default is 6..128. + # config.password_length = 6..128 + + # Email regex used to validate email formats. It simply asserts that + # an one (and only one) @ exists in the given string. This is mainly + # to give user feedback and not to assert the e-mail validity. + # config.email_regexp = /\A[^@]+@[^@]+\z/ + + # ==> Configuration for :timeoutable + # The time you want to timeout the user session without activity. After this + # time the user will be asked for credentials again. Default is 30 minutes. + # config.timeout_in = 30.minutes + + # ==> Configuration for :lockable + # Defines which strategy will be used to lock an account. + # :failed_attempts = Locks an account after a number of failed attempts to sign in. + # :none = No lock strategy. You should handle locking by yourself. + # config.lock_strategy = :failed_attempts + + # Defines which key will be used when locking and unlocking an account + # config.unlock_keys = [ :email ] + + # Defines which strategy will be used to unlock an account. + # :email = Sends an unlock link to the user email + # :time = Re-enables login after a certain amount of time (see :unlock_in below) + # :both = Enables both strategies + # :none = No unlock strategy. You should handle unlocking by yourself. + # config.unlock_strategy = :both + + # Number of authentication tries before locking an account if lock_strategy + # is failed attempts. + # config.maximum_attempts = 20 + + # Time interval to unlock the account if :time is enabled as unlock_strategy. + # config.unlock_in = 1.hour + + # ==> Configuration for :recoverable + # + # Defines which key will be used when recovering the password for an account + # config.reset_password_keys = [ :email ] + + # Time interval you can reset your password with a reset password key. + # Don't put a too small interval or your users won't have the time to + # change their passwords. + config.reset_password_within = 6.hours + + # ==> Configuration for :encryptable + # Allow you to use another encryption algorithm besides bcrypt (default). You can use + # :sha1, :sha512 or encryptors from others authentication tools as :clearance_sha1, + # :authlogic_sha512 (then you should set stretches above to 20 for default behavior) + # and :restful_authentication_sha1 (then you should set stretches to 10, and copy + # REST_AUTH_SITE_KEY to pepper) + # config.encryptor = :sha512 + + # ==> Configuration for :token_authenticatable + # Defines name of the authentication token params key + # config.token_authentication_key = :auth_token + + # ==> Scopes configuration + # Turn scoped views on. Before rendering "sessions/new", it will first check for + # "users/sessions/new". It's turned off by default because it's slower if you + # are using only default views. + # config.scoped_views = false + + # Configure the default scope given to Warden. By default it's the first + # devise role declared in your routes (usually :user). + # config.default_scope = :user + + # Configure sign_out behavior. + # Sign_out action can be scoped (i.e. /users/sign_out affects only :user scope). + # The default is true, which means any logout action will sign out all active scopes. + # config.sign_out_all_scopes = true + + # ==> Navigation configuration + # Lists the formats that should be treated as navigational. Formats like + # :html, should redirect to the sign in page when the user does not have + # access, but formats like :xml or :json, should return 401. + # + # If you have any extra navigational formats, like :iphone or :mobile, you + # should add them to the navigational formats lists. + # + # The "*/*" below is required to match Internet Explorer requests. + # config.navigational_formats = ["*/*", :html] + + # The default HTTP method used to sign out a resource. Default is :delete. + config.sign_out_via = :delete + + # ==> OmniAuth + # Add a new OmniAuth provider. Check the wiki for more information on setting + # up on your models and hooks. + # config.omniauth :github, 'APP_ID', 'APP_SECRET', :scope => 'user,public_repo' + + # ==> Warden configuration + # If you want to use other strategies, that are not supported by Devise, or + # change the failure app, you can configure them inside the config.warden block. + # + # config.warden do |manager| + # manager.intercept_401 = false + # manager.default_strategies(:scope => :user).unshift :some_external_strategy + # end +end diff --git a/config/locales/devise.en.yml b/config/locales/devise.en.yml new file mode 100644 index 0000000..73df488 --- /dev/null +++ b/config/locales/devise.en.yml @@ -0,0 +1,57 @@ +# Additional translations at https://github.com/plataformatec/devise/wiki/I18n + +en: + errors: + messages: + expired: "has expired, please request a new one" + not_found: "not found" + already_confirmed: "was already confirmed, please try signing in" + not_locked: "was not locked" + not_saved: + one: "1 error prohibited this %{resource} from being saved:" + other: "%{count} errors prohibited this %{resource} from being saved:" + + devise: + failure: + already_authenticated: 'You are already signed in.' + unauthenticated: 'You need to sign in or sign up before continuing.' + unconfirmed: 'You have to confirm your account before continuing.' + locked: 'Your account is locked.' + invalid: 'Invalid email or password.' + invalid_token: 'Invalid authentication token.' + timeout: 'Your session expired, please sign in again to continue.' + inactive: 'Your account was not activated yet.' + sessions: + signed_in: 'Signed in successfully.' + signed_out: 'Signed out successfully.' + passwords: + send_instructions: 'You will receive an email with instructions about how to reset your password in a few minutes.' + updated: 'Your password was changed successfully. You are now signed in.' + updated_not_active: 'Your password was changed successfully.' + send_paranoid_instructions: "If your e-mail exists on our database, you will receive a password recovery link on your e-mail" + confirmations: + send_instructions: 'You will receive an email with instructions about how to confirm your account in a few minutes.' + send_paranoid_instructions: 'If your e-mail exists on our database, you will receive an email with instructions about how to confirm your account in a few minutes.' + confirmed: 'Your account was successfully confirmed. You are now signed in.' + registrations: + signed_up: 'Welcome! You have signed up successfully.' + signed_up_but_unconfirmed: 'A message with a confirmation link has been sent to your email address. Please open the link to activate your account.' + signed_up_but_inactive: 'You have signed up successfully. However, we could not sign you in because your account is not yet activated.' + signed_up_but_locked: 'You have signed up successfully. However, we could not sign you in because your account is locked.' + updated: 'You updated your account successfully.' + update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and click on the confirm link to finalize confirming your new email address." + destroyed: 'Bye! Your account was successfully cancelled. We hope to see you again soon.' + unlocks: + send_instructions: 'You will receive an email with instructions about how to unlock your account in a few minutes.' + unlocked: 'Your account has been unlocked successfully. Please sign in to continue.' + send_paranoid_instructions: 'If your account exists, you will receive an email with instructions about how to unlock it in a few minutes.' + omniauth_callbacks: + success: 'Successfully authorized from %{kind} account.' + failure: 'Could not authorize you from %{kind} because "%{reason}".' + mailer: + confirmation_instructions: + subject: 'Confirmation instructions' + reset_password_instructions: + subject: 'Reset password instructions' + unlock_instructions: + subject: 'Unlock Instructions' diff --git a/config/routes.rb b/config/routes.rb index 6231b71..f7ef331 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,5 +1,7 @@ Planet::Application.routes.draw do + devise_for :users + get "types/ordered_index" # se añade una nueva ruta a la acción "ordered_index" resources :sites diff --git a/db/migrate/20120415165600_devise_create_users.rb b/db/migrate/20120415165600_devise_create_users.rb new file mode 100644 index 0000000..540333c --- /dev/null +++ b/db/migrate/20120415165600_devise_create_users.rb @@ -0,0 +1,49 @@ +class DeviseCreateUsers < ActiveRecord::Migration + def change + create_table(:users) do |t| + ## Database authenticatable + t.string :email, :null => false, :default => "" + t.string :encrypted_password, :null => false, :default => "" + + ## Recoverable + t.string :reset_password_token + t.datetime :reset_password_sent_at + + ## Rememberable + t.datetime :remember_created_at + + ## Trackable + t.integer :sign_in_count, :default => 0 + t.datetime :current_sign_in_at + t.datetime :last_sign_in_at + t.string :current_sign_in_ip + t.string :last_sign_in_ip + + ## Encryptable + # t.string :password_salt + + ## Confirmable + # t.string :confirmation_token + # t.datetime :confirmed_at + # t.datetime :confirmation_sent_at + # t.string :unconfirmed_email # Only if using reconfirmable + + ## Lockable + # t.integer :failed_attempts, :default => 0 # Only if lock strategy is :failed_attempts + # t.string :unlock_token # Only if unlock strategy is :email or :both + # t.datetime :locked_at + + ## Token authenticatable + # t.string :authentication_token + + + t.timestamps + end + + add_index :users, :email, :unique => true + add_index :users, :reset_password_token, :unique => true + # add_index :users, :confirmation_token, :unique => true + # add_index :users, :unlock_token, :unique => true + # add_index :users, :authentication_token, :unique => true + end +end diff --git a/db/migrate/20120415170814_user_name.rb b/db/migrate/20120415170814_user_name.rb new file mode 100644 index 0000000..dfb5874 --- /dev/null +++ b/db/migrate/20120415170814_user_name.rb @@ -0,0 +1,13 @@ +class UserName < ActiveRecord::Migration + def up + change_table :users do |t| #añade la columna name a la tabla sites + t.column :name,:string + end + end + + def down + change_table :users do |t| + t.remove :name + end + end +end diff --git a/db/schema.rb b/db/schema.rb index de057ba..b36c7ab 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20120320100145) do +ActiveRecord::Schema.define(:version => 20120415170814) do create_table "sites", :force => true do |t| t.string "name" @@ -29,4 +29,25 @@ t.datetime "updated_at", :null => false end +#Tablas de users generada por devise con campos para gestión de usuarios y sesión + create_table "users", :force => true do |t| + t.string "email", :default => "", :null => false + t.string "encrypted_password", :default => "", :null => false + t.string "reset_password_token" + t.datetime "reset_password_sent_at" + t.datetime "remember_created_at" + t.integer "sign_in_count", :default => 0 + t.datetime "current_sign_in_at" + t.datetime "last_sign_in_at" + t.string "current_sign_in_ip" + t.string "last_sign_in_ip" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "name" + end + +#añaden índices de búsqueda de usuarios por email y por token de reset de pwd + add_index "users", ["email"], :name => "index_users_on_email", :unique => true + add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true + end diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml new file mode 100644 index 0000000..c63aac0 --- /dev/null +++ b/test/fixtures/users.yml @@ -0,0 +1,11 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html + +# This model initially had no columns defined. If you add columns to the +# model remove the '{}' from the fixture names and add the columns immediately +# below each fixture, per the syntax in the comments below +# +one: {} +# column: value +# +two: {} +# column: value diff --git a/test/unit/user_test.rb b/test/unit/user_test.rb new file mode 100644 index 0000000..82f61e0 --- /dev/null +++ b/test/unit/user_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class UserTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end From 527b3e515e368cc9fdb4fb0b95e305ebfde0db0b Mon Sep 17 00:00:00 2001 From: danirubio Date: Sun, 15 Apr 2012 19:19:18 +0200 Subject: [PATCH 09/21] generate devise:views --- app/views/devise/_links.erb | 25 +++++++++++++++++++ app/views/devise/confirmations/new.html.erb | 12 +++++++++ .../mailer/confirmation_instructions.html.erb | 5 ++++ .../reset_password_instructions.html.erb | 8 ++++++ .../mailer/unlock_instructions.html.erb | 7 ++++++ app/views/devise/passwords/edit.html.erb | 16 ++++++++++++ app/views/devise/passwords/new.html.erb | 12 +++++++++ app/views/devise/registrations/edit.html.erb | 25 +++++++++++++++++++ app/views/devise/registrations/new.html.erb | 18 +++++++++++++ app/views/devise/sessions/new.html.erb | 17 +++++++++++++ app/views/devise/unlocks/new.html.erb | 12 +++++++++ 11 files changed, 157 insertions(+) create mode 100644 app/views/devise/_links.erb create mode 100644 app/views/devise/confirmations/new.html.erb create mode 100644 app/views/devise/mailer/confirmation_instructions.html.erb create mode 100644 app/views/devise/mailer/reset_password_instructions.html.erb create mode 100644 app/views/devise/mailer/unlock_instructions.html.erb create mode 100644 app/views/devise/passwords/edit.html.erb create mode 100644 app/views/devise/passwords/new.html.erb create mode 100644 app/views/devise/registrations/edit.html.erb create mode 100644 app/views/devise/registrations/new.html.erb create mode 100644 app/views/devise/sessions/new.html.erb create mode 100644 app/views/devise/unlocks/new.html.erb diff --git a/app/views/devise/_links.erb b/app/views/devise/_links.erb new file mode 100644 index 0000000..eab783a --- /dev/null +++ b/app/views/devise/_links.erb @@ -0,0 +1,25 @@ +<%- if controller_name != 'sessions' %> + <%= link_to "Sign in", new_session_path(resource_name) %>
+<% end -%> + +<%- if devise_mapping.registerable? && controller_name != 'registrations' %> + <%= link_to "Sign up", new_registration_path(resource_name) %>
+<% end -%> + +<%- if devise_mapping.recoverable? && controller_name != 'passwords' %> + <%= link_to "Forgot your password?", new_password_path(resource_name) %>
+<% end -%> + +<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %> + <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %>
+<% end -%> + +<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %> + <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %>
+<% end -%> + +<%- if devise_mapping.omniauthable? %> + <%- resource_class.omniauth_providers.each do |provider| %> + <%= link_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider) %>
+ <% end -%> +<% end -%> \ No newline at end of file diff --git a/app/views/devise/confirmations/new.html.erb b/app/views/devise/confirmations/new.html.erb new file mode 100644 index 0000000..18d81b1 --- /dev/null +++ b/app/views/devise/confirmations/new.html.erb @@ -0,0 +1,12 @@ +

Resend confirmation instructions

+ +<%= form_for(resource, :as => resource_name, :url => confirmation_path(resource_name), :html => { :method => :post }) do |f| %> + <%= devise_error_messages! %> + +
<%= f.label :email %>
+ <%= f.email_field :email %>
+ +
<%= f.submit "Resend confirmation instructions" %>
+<% end %> + +<%= render "links" %> \ No newline at end of file diff --git a/app/views/devise/mailer/confirmation_instructions.html.erb b/app/views/devise/mailer/confirmation_instructions.html.erb new file mode 100644 index 0000000..a5c4585 --- /dev/null +++ b/app/views/devise/mailer/confirmation_instructions.html.erb @@ -0,0 +1,5 @@ +

Welcome <%= @resource.email %>!

+ +

You can confirm your account email through the link below:

+ +

<%= link_to 'Confirm my account', confirmation_url(@resource, :confirmation_token => @resource.confirmation_token) %>

diff --git a/app/views/devise/mailer/reset_password_instructions.html.erb b/app/views/devise/mailer/reset_password_instructions.html.erb new file mode 100644 index 0000000..ae9e888 --- /dev/null +++ b/app/views/devise/mailer/reset_password_instructions.html.erb @@ -0,0 +1,8 @@ +

Hello <%= @resource.email %>!

+ +

Someone has requested a link to change your password, and you can do this through the link below.

+ +

<%= link_to 'Change my password', edit_password_url(@resource, :reset_password_token => @resource.reset_password_token) %>

+ +

If you didn't request this, please ignore this email.

+

Your password won't change until you access the link above and create a new one.

diff --git a/app/views/devise/mailer/unlock_instructions.html.erb b/app/views/devise/mailer/unlock_instructions.html.erb new file mode 100644 index 0000000..2263c21 --- /dev/null +++ b/app/views/devise/mailer/unlock_instructions.html.erb @@ -0,0 +1,7 @@ +

Hello <%= @resource.email %>!

+ +

Your account has been locked due to an excessive amount of unsuccessful sign in attempts.

+ +

Click the link below to unlock your account:

+ +

<%= link_to 'Unlock my account', unlock_url(@resource, :unlock_token => @resource.unlock_token) %>

diff --git a/app/views/devise/passwords/edit.html.erb b/app/views/devise/passwords/edit.html.erb new file mode 100644 index 0000000..5f7bcf8 --- /dev/null +++ b/app/views/devise/passwords/edit.html.erb @@ -0,0 +1,16 @@ +

Change your password

+ +<%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :put }) do |f| %> + <%= devise_error_messages! %> + <%= f.hidden_field :reset_password_token %> + +
<%= f.label :password, "New password" %>
+ <%= f.password_field :password %>
+ +
<%= f.label :password_confirmation, "Confirm new password" %>
+ <%= f.password_field :password_confirmation %>
+ +
<%= f.submit "Change my password" %>
+<% end %> + +<%= render "links" %> \ No newline at end of file diff --git a/app/views/devise/passwords/new.html.erb b/app/views/devise/passwords/new.html.erb new file mode 100644 index 0000000..b0b5690 --- /dev/null +++ b/app/views/devise/passwords/new.html.erb @@ -0,0 +1,12 @@ +

Forgot your password?

+ +<%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :post }) do |f| %> + <%= devise_error_messages! %> + +
<%= f.label :email %>
+ <%= f.email_field :email %>
+ +
<%= f.submit "Send me reset password instructions" %>
+<% end %> + +<%= render "links" %> \ No newline at end of file diff --git a/app/views/devise/registrations/edit.html.erb b/app/views/devise/registrations/edit.html.erb new file mode 100644 index 0000000..bb66fbf --- /dev/null +++ b/app/views/devise/registrations/edit.html.erb @@ -0,0 +1,25 @@ +

Edit <%= resource_name.to_s.humanize %>

+ +<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f| %> + <%= devise_error_messages! %> + +
<%= f.label :email %>
+ <%= f.email_field :email %>
+ +
<%= f.label :password %> (leave blank if you don't want to change it)
+ <%= f.password_field :password, :autocomplete => "off" %>
+ +
<%= f.label :password_confirmation %>
+ <%= f.password_field :password_confirmation %>
+ +
<%= f.label :current_password %> (we need your current password to confirm your changes)
+ <%= f.password_field :current_password %>
+ +
<%= f.submit "Update" %>
+<% end %> + +

Cancel my account

+ +

Unhappy? <%= link_to "Cancel my account", registration_path(resource_name), :confirm => "Are you sure?", :method => :delete %>.

+ +<%= link_to "Back", :back %> diff --git a/app/views/devise/registrations/new.html.erb b/app/views/devise/registrations/new.html.erb new file mode 100644 index 0000000..f5136f1 --- /dev/null +++ b/app/views/devise/registrations/new.html.erb @@ -0,0 +1,18 @@ +

Sign up

+ +<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %> + <%= devise_error_messages! %> + +
<%= f.label :email %>
+ <%= f.email_field :email %>
+ +
<%= f.label :password %>
+ <%= f.password_field :password %>
+ +
<%= f.label :password_confirmation %>
+ <%= f.password_field :password_confirmation %>
+ +
<%= f.submit "Sign up" %>
+<% end %> + +<%= render "links" %> diff --git a/app/views/devise/sessions/new.html.erb b/app/views/devise/sessions/new.html.erb new file mode 100644 index 0000000..f12116b --- /dev/null +++ b/app/views/devise/sessions/new.html.erb @@ -0,0 +1,17 @@ +

Sign in

+ +<%= form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f| %> +
<%= f.label :email %>
+ <%= f.email_field :email %>
+ +
<%= f.label :password %>
+ <%= f.password_field :password %>
+ + <% if devise_mapping.rememberable? -%> +
<%= f.check_box :remember_me %> <%= f.label :remember_me %>
+ <% end -%> + +
<%= f.submit "Sign in" %>
+<% end %> + +<%= render "links" %> \ No newline at end of file diff --git a/app/views/devise/unlocks/new.html.erb b/app/views/devise/unlocks/new.html.erb new file mode 100644 index 0000000..0dc79ac --- /dev/null +++ b/app/views/devise/unlocks/new.html.erb @@ -0,0 +1,12 @@ +

Resend unlock instructions

+ +<%= form_for(resource, :as => resource_name, :url => unlock_path(resource_name), :html => { :method => :post }) do |f| %> + <%= devise_error_messages! %> + +
<%= f.label :email %>
+ <%= f.email_field :email %>
+ +
<%= f.submit "Resend unlock instructions" %>
+<% end %> + +<%= render "links" %> \ No newline at end of file From 0693347ab0aa83a54986866bc7e3e8c3272e01b9 Mon Sep 17 00:00:00 2001 From: danirubio Date: Sun, 15 Apr 2012 19:49:53 +0200 Subject: [PATCH 10/21] adaptar vistas devise --- app/assets/stylesheets/planet.css | 7 +++++++ app/views/devise/registrations/edit.html.erb | 3 +++ app/views/devise/registrations/new.html.erb | 3 +++ app/views/layouts/application.html.erb | 12 +++++++++++- 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/planet.css b/app/assets/stylesheets/planet.css index 9f8fd4c..213dfbf 100644 --- a/app/assets/stylesheets/planet.css +++ b/app/assets/stylesheets/planet.css @@ -91,6 +91,13 @@ text-align: center; } +/* Estilo para el banner de registro de usuarios */ +#banner .user { + float: right; + color: #bfb; + font-size: small; +} + #banner img { float: left; padding-left: 10px; diff --git a/app/views/devise/registrations/edit.html.erb b/app/views/devise/registrations/edit.html.erb index bb66fbf..a133d4c 100644 --- a/app/views/devise/registrations/edit.html.erb +++ b/app/views/devise/registrations/edit.html.erb @@ -3,6 +3,9 @@ <%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f| %> <%= devise_error_messages! %> +

<%= f.label :name %>
+ <%= f.text_field :name %>

+
<%= f.label :email %>
<%= f.email_field :email %>
diff --git a/app/views/devise/registrations/new.html.erb b/app/views/devise/registrations/new.html.erb index f5136f1..ba81cb3 100644 --- a/app/views/devise/registrations/new.html.erb +++ b/app/views/devise/registrations/new.html.erb @@ -3,6 +3,9 @@ <%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %> <%= devise_error_messages! %> +

<%= f.label :name %>
+ <%= f.text_field :name %>

+
<%= f.label :email %>
<%= f.email_field :email %>
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index fbc0caa..4f9f37a 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -17,6 +17,14 @@
<%= yield %>
\ No newline at end of file From 0f10122c90d97dc4b1aac19964a1a3ec8703f3d8 Mon Sep 17 00:00:00 2001 From: danirubio Date: Sun, 15 Apr 2012 20:01:08 +0200 Subject: [PATCH 11/21] User Sites relation --- app/models/site.rb | 3 +++ app/models/user.rb | 2 ++ db/migrate/20120415175047_user_sites.rb | 13 +++++++++++++ db/schema.rb | 5 ++--- 4 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 db/migrate/20120415175047_user_sites.rb diff --git a/app/models/site.rb b/app/models/site.rb index 3eb288d..671cc6c 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -1,3 +1,6 @@ class Site < ActiveRecord::Base belongs_to :type + belongs_to :user + + attr_protected :user_id end diff --git a/app/models/user.rb b/app/models/user.rb index 1591323..6aa676c 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -4,6 +4,8 @@ class User < ActiveRecord::Base devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable + has_many :sites + # Setup accessible (or protected) attributes for your model attr_accessible :name,:email, :password, :password_confirmation, :remember_me end diff --git a/db/migrate/20120415175047_user_sites.rb b/db/migrate/20120415175047_user_sites.rb new file mode 100644 index 0000000..c0b05f3 --- /dev/null +++ b/db/migrate/20120415175047_user_sites.rb @@ -0,0 +1,13 @@ +class UserSites < ActiveRecord::Migration + def up + change_table :sites do |t| #añade la columna user_id a la tabla sites + t.column :user_id, :integer + end + end + + def down + change_table :sites do |t| + t.remove :user_id + end + end +end diff --git a/db/schema.rb b/db/schema.rb index b36c7ab..61e392c 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20120415170814) do +ActiveRecord::Schema.define(:version => 20120415175047) do create_table "sites", :force => true do |t| t.string "name" @@ -20,6 +20,7 @@ t.string "image_url" t.datetime "created_at", :null => false t.datetime "updated_at", :null => false + t.integer "user_id" end create_table "types", :force => true do |t| @@ -29,7 +30,6 @@ t.datetime "updated_at", :null => false end -#Tablas de users generada por devise con campos para gestión de usuarios y sesión create_table "users", :force => true do |t| t.string "email", :default => "", :null => false t.string "encrypted_password", :default => "", :null => false @@ -46,7 +46,6 @@ t.string "name" end -#añaden índices de búsqueda de usuarios por email y por token de reset de pwd add_index "users", ["email"], :name => "index_users_on_email", :unique => true add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true From 7b0d33b754c315abe82f14d767e30c5eba11908d Mon Sep 17 00:00:00 2001 From: danirubio Date: Sun, 15 Apr 2012 20:27:54 +0200 Subject: [PATCH 12/21] generate devise:views --- app/controllers/sites_controller.rb | 14 +++++++++----- app/views/sites/index.html.erb | 10 ++++++---- app/views/sites/show.html.erb | 9 +++++++-- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/app/controllers/sites_controller.rb b/app/controllers/sites_controller.rb index f3ae9ad..510b8ab 100644 --- a/app/controllers/sites_controller.rb +++ b/app/controllers/sites_controller.rb @@ -1,4 +1,8 @@ class SitesController < ApplicationController + + # authenticate_user! ejecuta acción sólo si sesión existe + before_filter :authenticate_user!,:except=> [:index,:show] + # GET /sites # GET /sites.json def index @@ -27,7 +31,7 @@ def show # GET /sites/new # GET /sites/new.json def new - @site = Site.new + @site = current_user.sites.build #cambio Site por current_user.sites.build -- crea sitio vacio asociado a current_user respond_to do |format| format.html # new.html.erb @@ -37,13 +41,13 @@ def new # GET /sites/1/edit def edit - @site = Site.find(params[:id]) + @site = current_user.sites.find(params[:id]) #cambio Site por current_user.sites -- busca solo en sitios asociados a current_user end # POST /sites # POST /sites.json def create - @site = Site.new(params[:site]) + @site = current_user.sites.build(params[:site]) #cambio Site.new por current_user.sites.build -- asigna solo si sitio asociado a current_user respond_to do |format| if @site.save @@ -59,7 +63,7 @@ def create # PUT /sites/1 # PUT /sites/1.json def update - @site = Site.find(params[:id]) + @site = current_user.sites.find(params[:id]) #cambio Site por current_user.sites.-- busca solo en sitios asociados a current_user respond_to do |format| if @site.update_attributes(params[:site]) @@ -75,7 +79,7 @@ def update # DELETE /sites/1 # DELETE /sites/1.json def destroy - @site = Site.find(params[:id]) + @site = current_user.sites.find(params[:id]) #cambiar Site por current_user.sites -- busca solo en sitios asociados a current_user @site.destroy respond_to do |format| diff --git a/app/views/sites/index.html.erb b/app/views/sites/index.html.erb index f1034b8..a2627ae 100644 --- a/app/views/sites/index.html.erb +++ b/app/views/sites/index.html.erb @@ -19,10 +19,12 @@ <%= link_to 'Show', site %>
- <%= link_to 'Edit', edit_site_path(site) %>
- <%= link_to 'Destroy', site, - :confirm => 'Are you sure?', - :method => :delete %> + <% if site.user == current_user %> + <%= link_to 'Edit', edit_site_path(site) %>
+ <%= link_to 'Destroy', site, + :confirm => 'Are you sure?', + :method => :delete %> + <% end %> <% end %> diff --git a/app/views/sites/show.html.erb b/app/views/sites/show.html.erb index 94dc17a..4655c44 100644 --- a/app/views/sites/show.html.erb +++ b/app/views/sites/show.html.erb @@ -8,8 +8,13 @@

<%=sanitize @site.description %>

+

Autor: + <%= @site.user.name if @site.user %>

+ +

-

-<%= link_to 'Edit', edit_site_path(@site) %> | +<% if @site.user == current_user %> + <%= link_to 'Edit', edit_site_path(@site) %> | +<% end %> <%= link_to 'Back', sites_path %> From d4b46b80be37d870b2d5c03c12c1cc250dd7fcf3 Mon Sep 17 00:00:00 2001 From: danirubio Date: Sun, 15 Apr 2012 20:54:55 +0200 Subject: [PATCH 13/21] creacion de scaffold comments --- app/assets/javascripts/comments.js.coffee | 3 + app/assets/stylesheets/comments.css.scss | 3 + app/controllers/comments_controller.rb | 83 ++++++++++++++++++++ app/helpers/comments_helper.rb | 2 + app/models/comment.rb | 2 + app/views/comments/_form.html.erb | 29 +++++++ app/views/comments/edit.html.erb | 6 ++ app/views/comments/index.html.erb | 27 +++++++ app/views/comments/new.html.erb | 5 ++ app/views/comments/show.html.erb | 20 +++++ config/routes.rb | 2 + db/migrate/20120415184215_create_comments.rb | 11 +++ db/schema.rb | 10 ++- test/fixtures/comments.yml | 11 +++ test/functional/comments_controller_test.rb | 49 ++++++++++++ test/unit/comment_test.rb | 7 ++ test/unit/helpers/comments_helper_test.rb | 4 + 17 files changed, 273 insertions(+), 1 deletion(-) create mode 100644 app/assets/javascripts/comments.js.coffee create mode 100644 app/assets/stylesheets/comments.css.scss create mode 100644 app/controllers/comments_controller.rb create mode 100644 app/helpers/comments_helper.rb create mode 100644 app/models/comment.rb create mode 100644 app/views/comments/_form.html.erb create mode 100644 app/views/comments/edit.html.erb create mode 100644 app/views/comments/index.html.erb create mode 100644 app/views/comments/new.html.erb create mode 100644 app/views/comments/show.html.erb create mode 100644 db/migrate/20120415184215_create_comments.rb create mode 100644 test/fixtures/comments.yml create mode 100644 test/functional/comments_controller_test.rb create mode 100644 test/unit/comment_test.rb create mode 100644 test/unit/helpers/comments_helper_test.rb diff --git a/app/assets/javascripts/comments.js.coffee b/app/assets/javascripts/comments.js.coffee new file mode 100644 index 0000000..7615679 --- /dev/null +++ b/app/assets/javascripts/comments.js.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ diff --git a/app/assets/stylesheets/comments.css.scss b/app/assets/stylesheets/comments.css.scss new file mode 100644 index 0000000..3722c12 --- /dev/null +++ b/app/assets/stylesheets/comments.css.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the comments controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb new file mode 100644 index 0000000..dfb5f63 --- /dev/null +++ b/app/controllers/comments_controller.rb @@ -0,0 +1,83 @@ +class CommentsController < ApplicationController + # GET /comments + # GET /comments.json + def index + @comments = Comment.all + + respond_to do |format| + format.html # index.html.erb + format.json { render json: @comments } + end + end + + # GET /comments/1 + # GET /comments/1.json + def show + @comment = Comment.find(params[:id]) + + respond_to do |format| + format.html # show.html.erb + format.json { render json: @comment } + end + end + + # GET /comments/new + # GET /comments/new.json + def new + @comment = Comment.new + + respond_to do |format| + format.html # new.html.erb + format.json { render json: @comment } + end + end + + # GET /comments/1/edit + def edit + @comment = Comment.find(params[:id]) + end + + # POST /comments + # POST /comments.json + def create + @comment = Comment.new(params[:comment]) + + respond_to do |format| + if @comment.save + format.html { redirect_to @comment, notice: 'Comment was successfully created.' } + format.json { render json: @comment, status: :created, location: @comment } + else + format.html { render action: "new" } + format.json { render json: @comment.errors, status: :unprocessable_entity } + end + end + end + + # PUT /comments/1 + # PUT /comments/1.json + def update + @comment = Comment.find(params[:id]) + + respond_to do |format| + if @comment.update_attributes(params[:comment]) + format.html { redirect_to @comment, notice: 'Comment was successfully updated.' } + format.json { head :no_content } + else + format.html { render action: "edit" } + format.json { render json: @comment.errors, status: :unprocessable_entity } + end + end + end + + # DELETE /comments/1 + # DELETE /comments/1.json + def destroy + @comment = Comment.find(params[:id]) + @comment.destroy + + respond_to do |format| + format.html { redirect_to comments_url } + format.json { head :no_content } + end + end +end diff --git a/app/helpers/comments_helper.rb b/app/helpers/comments_helper.rb new file mode 100644 index 0000000..0ec9ca5 --- /dev/null +++ b/app/helpers/comments_helper.rb @@ -0,0 +1,2 @@ +module CommentsHelper +end diff --git a/app/models/comment.rb b/app/models/comment.rb new file mode 100644 index 0000000..45b2d38 --- /dev/null +++ b/app/models/comment.rb @@ -0,0 +1,2 @@ +class Comment < ActiveRecord::Base +end diff --git a/app/views/comments/_form.html.erb b/app/views/comments/_form.html.erb new file mode 100644 index 0000000..3036a7c --- /dev/null +++ b/app/views/comments/_form.html.erb @@ -0,0 +1,29 @@ +<%= form_for(@comment) do |f| %> + <% if @comment.errors.any? %> +

+

<%= pluralize(@comment.errors.count, "error") %> prohibited this comment from being saved:

+ +
    + <% @comment.errors.full_messages.each do |msg| %> +
  • <%= msg %>
  • + <% end %> +
+
+ <% end %> + +
+ <%= f.label :comment %>
+ <%= f.text_field :comment %> +
+
+ <%= f.label :user_id %>
+ <%= f.number_field :user_id %> +
+
+ <%= f.label :site_id %>
+ <%= f.number_field :site_id %> +
+
+ <%= f.submit %> +
+<% end %> diff --git a/app/views/comments/edit.html.erb b/app/views/comments/edit.html.erb new file mode 100644 index 0000000..12ea7f9 --- /dev/null +++ b/app/views/comments/edit.html.erb @@ -0,0 +1,6 @@ +

Editing comment

+ +<%= render 'form' %> + +<%= link_to 'Show', @comment %> | +<%= link_to 'Back', comments_path %> diff --git a/app/views/comments/index.html.erb b/app/views/comments/index.html.erb new file mode 100644 index 0000000..b3c1394 --- /dev/null +++ b/app/views/comments/index.html.erb @@ -0,0 +1,27 @@ +

Listing comments

+ + + + + + + + + + + +<% @comments.each do |comment| %> + + + + + + + + +<% end %> +
CommentUserSite
<%= comment.comment %><%= comment.user_id %><%= comment.site_id %><%= link_to 'Show', comment %><%= link_to 'Edit', edit_comment_path(comment) %><%= link_to 'Destroy', comment, confirm: 'Are you sure?', method: :delete %>
+ +
+ +<%= link_to 'New Comment', new_comment_path %> diff --git a/app/views/comments/new.html.erb b/app/views/comments/new.html.erb new file mode 100644 index 0000000..07a754a --- /dev/null +++ b/app/views/comments/new.html.erb @@ -0,0 +1,5 @@ +

New comment

+ +<%= render 'form' %> + +<%= link_to 'Back', comments_path %> diff --git a/app/views/comments/show.html.erb b/app/views/comments/show.html.erb new file mode 100644 index 0000000..b375949 --- /dev/null +++ b/app/views/comments/show.html.erb @@ -0,0 +1,20 @@ +

<%= notice %>

+ +

+ Comment: + <%= @comment.comment %> +

+ +

+ User: + <%= @comment.user_id %> +

+ +

+ Site: + <%= @comment.site_id %> +

+ + +<%= link_to 'Edit', edit_comment_path(@comment) %> | +<%= link_to 'Back', comments_path %> diff --git a/config/routes.rb b/config/routes.rb index f7ef331..0bc8f92 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,5 +1,7 @@ Planet::Application.routes.draw do + resources :comments + devise_for :users get "types/ordered_index" # se añade una nueva ruta a la acción "ordered_index" diff --git a/db/migrate/20120415184215_create_comments.rb b/db/migrate/20120415184215_create_comments.rb new file mode 100644 index 0000000..36d0b14 --- /dev/null +++ b/db/migrate/20120415184215_create_comments.rb @@ -0,0 +1,11 @@ +class CreateComments < ActiveRecord::Migration + def change + create_table :comments do |t| + t.string :comment + t.integer :user_id + t.integer :site_id + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 61e392c..6dc94e8 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,15 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20120415175047) do +ActiveRecord::Schema.define(:version => 20120415184215) do + + create_table "comments", :force => true do |t| + t.string "comment" + t.integer "user_id" + t.integer "site_id" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end create_table "sites", :force => true do |t| t.string "name" diff --git a/test/fixtures/comments.yml b/test/fixtures/comments.yml new file mode 100644 index 0000000..29c9999 --- /dev/null +++ b/test/fixtures/comments.yml @@ -0,0 +1,11 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html + +one: + comment: MyString + user_id: 1 + site_id: 1 + +two: + comment: MyString + user_id: 1 + site_id: 1 diff --git a/test/functional/comments_controller_test.rb b/test/functional/comments_controller_test.rb new file mode 100644 index 0000000..b2b500c --- /dev/null +++ b/test/functional/comments_controller_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class CommentsControllerTest < ActionController::TestCase + setup do + @comment = comments(:one) + end + + test "should get index" do + get :index + assert_response :success + assert_not_nil assigns(:comments) + end + + test "should get new" do + get :new + assert_response :success + end + + test "should create comment" do + assert_difference('Comment.count') do + post :create, comment: @comment.attributes + end + + assert_redirected_to comment_path(assigns(:comment)) + end + + test "should show comment" do + get :show, id: @comment + assert_response :success + end + + test "should get edit" do + get :edit, id: @comment + assert_response :success + end + + test "should update comment" do + put :update, id: @comment, comment: @comment.attributes + assert_redirected_to comment_path(assigns(:comment)) + end + + test "should destroy comment" do + assert_difference('Comment.count', -1) do + delete :destroy, id: @comment + end + + assert_redirected_to comments_path + end +end diff --git a/test/unit/comment_test.rb b/test/unit/comment_test.rb new file mode 100644 index 0000000..b6d6131 --- /dev/null +++ b/test/unit/comment_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class CommentTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/unit/helpers/comments_helper_test.rb b/test/unit/helpers/comments_helper_test.rb new file mode 100644 index 0000000..2518c16 --- /dev/null +++ b/test/unit/helpers/comments_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class CommentsHelperTest < ActionView::TestCase +end From b61b138c2533233c9a9a04630759f8eceec33268 Mon Sep 17 00:00:00 2001 From: danirubio Date: Sun, 15 Apr 2012 23:05:54 +0200 Subject: [PATCH 14/21] version final Entrega 6 --- app/controllers/comments_controller.rb | 21 +++++++++++++++------ app/controllers/sites_controller.rb | 1 + app/models/comment.rb | 4 ++++ app/models/site.rb | 2 ++ app/models/user.rb | 1 + app/views/comments/edit.html.erb | 8 +++++++- app/views/comments/index.html.erb | 7 +++---- app/views/comments/new.html.erb | 8 +++++++- app/views/comments/show.html.erb | 12 +++++++----- app/views/sites/index.html.erb | 5 +++++ app/views/sites/show.html.erb | 3 +++ config/routes.rb | 8 +++++--- 12 files changed, 60 insertions(+), 20 deletions(-) diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb index dfb5f63..a754701 100644 --- a/app/controllers/comments_controller.rb +++ b/app/controllers/comments_controller.rb @@ -1,8 +1,17 @@ class CommentsController < ApplicationController + + # authenticate_user! ejecuta acción sólo si sesión existe + before_filter :authenticate_user!,:except=> [:index,:show] + # GET /comments # GET /comments.json def index - @comments = Comment.all + if params[:type_id].nil? or params[:type_id].empty? + @comments = Comment.all + else + @@comments = Comment.find(params[:type_id]).sites + end + # si no funciona cambiar esto por comments=comment.all q es lo q estaba respond_to do |format| format.html # index.html.erb @@ -24,7 +33,7 @@ def show # GET /comments/new # GET /comments/new.json def new - @comment = Comment.new + @comment = current_user.comments.build#cambio comment por current_user.comments.build -- crea comentario vacio asociado a current_user respond_to do |format| format.html # new.html.erb @@ -34,13 +43,13 @@ def new # GET /comments/1/edit def edit - @comment = Comment.find(params[:id]) + @comment = current_user.comments.find(params[:id]) #cambio Comment por current_user.comments -- busca solo en comentarios asociados a current_user end # POST /comments # POST /comments.json def create - @comment = Comment.new(params[:comment]) + @comment = current_user.comments.build(params[:comment]) #cambio Comment.new por current_user.comments.build -- asigna solo si comentario asociado a current_user respond_to do |format| if @comment.save @@ -56,7 +65,7 @@ def create # PUT /comments/1 # PUT /comments/1.json def update - @comment = Comment.find(params[:id]) + @comment = current_user.comments.find(params[:id]) #cambio Comment por current_user.comments.-- busca solo en comentarios asociados a current_user respond_to do |format| if @comment.update_attributes(params[:comment]) @@ -72,7 +81,7 @@ def update # DELETE /comments/1 # DELETE /comments/1.json def destroy - @comment = Comment.find(params[:id]) + @comment = current_user.comments.find(params[:id]) #cambiar Comment por current_user.comments -- busca solo en comentarios asociados a current_user @comment.destroy respond_to do |format| diff --git a/app/controllers/sites_controller.rb b/app/controllers/sites_controller.rb index 510b8ab..3baa68e 100644 --- a/app/controllers/sites_controller.rb +++ b/app/controllers/sites_controller.rb @@ -11,6 +11,7 @@ def index else @sites = Type.find(params[:type_id]).sites # path: /types/id/sites end + respond_to do |format| format.html # index.html.erb format.json { render json: @sites } diff --git a/app/models/comment.rb b/app/models/comment.rb index 45b2d38..5195ada 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -1,2 +1,6 @@ class Comment < ActiveRecord::Base + belongs_to :site + belongs_to :user + + attr_protected :user_id, :site_id end diff --git a/app/models/site.rb b/app/models/site.rb index 671cc6c..b9d0266 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -2,5 +2,7 @@ class Site < ActiveRecord::Base belongs_to :type belongs_to :user + has_many :comments + attr_protected :user_id end diff --git a/app/models/user.rb b/app/models/user.rb index 6aa676c..c3a8e3e 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -5,6 +5,7 @@ class User < ActiveRecord::Base :recoverable, :rememberable, :trackable, :validatable has_many :sites + has_many :comments # Setup accessible (or protected) attributes for your model attr_accessible :name,:email, :password, :password_confirmation, :remember_me diff --git a/app/views/comments/edit.html.erb b/app/views/comments/edit.html.erb index 12ea7f9..3112283 100644 --- a/app/views/comments/edit.html.erb +++ b/app/views/comments/edit.html.erb @@ -1,6 +1,12 @@

Editing comment

-<%= render 'form' %> +<%= form_for(@comment) do |f| %> + + <%= f.label :comment %>
+ <%= f.text_area :comment, :characters=>240 %>
+ +
<%= f.submit "Submit new comment" %>
+<% end %> <%= link_to 'Show', @comment %> | <%= link_to 'Back', comments_path %> diff --git a/app/views/comments/index.html.erb b/app/views/comments/index.html.erb index b3c1394..60eeab4 100644 --- a/app/views/comments/index.html.erb +++ b/app/views/comments/index.html.erb @@ -2,18 +2,17 @@ - + - <% @comments.each do |comment| %> + - @@ -24,4 +23,4 @@
-<%= link_to 'New Comment', new_comment_path %> +<%= link_to 'New Comment', new_comment_path %> \ No newline at end of file diff --git a/app/views/comments/new.html.erb b/app/views/comments/new.html.erb index 07a754a..9d37ba1 100644 --- a/app/views/comments/new.html.erb +++ b/app/views/comments/new.html.erb @@ -1,5 +1,11 @@

New comment

-<%= render 'form' %> +<%= form_for(@comment) do |f| %> + + <%= f.label :comment %>
+ <%= f.text_area :comment, :characters=>240 %>
+ +
<%= f.submit "Submit comment" %>
+<% end %> <%= link_to 'Back', comments_path %> diff --git a/app/views/comments/show.html.erb b/app/views/comments/show.html.erb index b375949..70a71e7 100644 --- a/app/views/comments/show.html.erb +++ b/app/views/comments/show.html.erb @@ -1,13 +1,13 @@

<%= notice %>

- Comment: - <%= @comment.comment %> + User: + <%= @comment.user.name %>

- User: - <%= @comment.user_id %> + Comment: + <%= @comment.comment %>

@@ -16,5 +16,7 @@

-<%= link_to 'Edit', edit_comment_path(@comment) %> | +<% if @comment.user == current_user %> + <%= link_to 'Edit', edit_comment_path(@comment) %> | +<% end %> <%= link_to 'Back', comments_path %> diff --git a/app/views/sites/index.html.erb b/app/views/sites/index.html.erb index a2627ae..31f84d3 100644 --- a/app/views/sites/index.html.erb +++ b/app/views/sites/index.html.erb @@ -25,6 +25,11 @@ :confirm => 'Are you sure?', :method => :delete %> <% end %> + + + <% if site.comments %> + <%= link_to 'Comments', comments_path %>
+ <% end %> <% end %> diff --git a/app/views/sites/show.html.erb b/app/views/sites/show.html.erb index 4655c44..310b5ae 100644 --- a/app/views/sites/show.html.erb +++ b/app/views/sites/show.html.erb @@ -11,6 +11,9 @@

Autor: <%= @site.user.name if @site.user %>

+

Comentarios: + <%= @site.comments if @site.comments %>

+

diff --git a/config/routes.rb b/config/routes.rb index 0bc8f92..0f8693c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,12 +1,14 @@ Planet::Application.routes.draw do - resources :comments - devise_for :users get "types/ordered_index" # se añade una nueva ruta a la acción "ordered_index" - resources :sites + resources :sites do + resources :comments + end + + resources :comments resources :types do # Rutas anidadas /types/id/sites..., resources :sites, :only => [ :index ] # Restringe a acción “index” From 22bccf2802073c94e0c2159d2c5b39706ab37f23 Mon Sep 17 00:00:00 2001 From: danirubio Date: Wed, 18 Apr 2012 19:28:52 +0200 Subject: [PATCH 15/21] solucionados fallos con comments de Entrega 6 --- app/controllers/comments_controller.rb | 11 +++--- app/controllers/sites_controller.rb | 11 ++++++ app/models/comment.rb | 7 ++-- app/models/site.rb | 6 ++++ app/models/type.rb | 4 +++ app/models/user.rb | 5 ++- app/views/comments/_form.html.erb | 11 +++--- app/views/comments/edit.html.erb | 28 ++++++++++++--- app/views/comments/index.html.erb | 48 ++++++++++++++------------ app/views/comments/new.html.erb | 10 ++---- app/views/comments/show.html.erb | 6 ++-- app/views/layouts/application.html.erb | 12 +++++++ app/views/sites/_form.html.erb | 17 ++++++++- app/views/sites/edit.html.erb | 2 +- app/views/sites/index.html.erb | 14 ++++---- app/views/sites/new.html.erb | 22 ++++++++++++ app/views/sites/show.html.erb | 11 +++--- config/routes.rb | 13 +++---- 18 files changed, 165 insertions(+), 73 deletions(-) diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb index a754701..715bc25 100644 --- a/app/controllers/comments_controller.rb +++ b/app/controllers/comments_controller.rb @@ -6,12 +6,11 @@ class CommentsController < ApplicationController # GET /comments # GET /comments.json def index - if params[:type_id].nil? or params[:type_id].empty? + if params[:site_id].nil? or params[:site_id].empty? @comments = Comment.all else - @@comments = Comment.find(params[:type_id]).sites + @comments = Site.find(params[:site_id]).comments end - # si no funciona cambiar esto por comments=comment.all q es lo q estaba respond_to do |format| format.html # index.html.erb @@ -33,7 +32,7 @@ def show # GET /comments/new # GET /comments/new.json def new - @comment = current_user.comments.build#cambio comment por current_user.comments.build -- crea comentario vacio asociado a current_user + @comment = current_user.comments.build #cambio comment por current_user.comments.build -- crea comentario vacio asociado a current_user respond_to do |format| format.html # new.html.erb @@ -50,7 +49,7 @@ def edit # POST /comments.json def create @comment = current_user.comments.build(params[:comment]) #cambio Comment.new por current_user.comments.build -- asigna solo si comentario asociado a current_user - + respond_to do |format| if @comment.save format.html { redirect_to @comment, notice: 'Comment was successfully created.' } @@ -85,7 +84,7 @@ def destroy @comment.destroy respond_to do |format| - format.html { redirect_to comments_url } + format.html { redirect_to sites_url } #cambiar por sites_comments_url¿?¿? format.json { head :no_content } end end diff --git a/app/controllers/sites_controller.rb b/app/controllers/sites_controller.rb index 3baa68e..def2078 100644 --- a/app/controllers/sites_controller.rb +++ b/app/controllers/sites_controller.rb @@ -3,6 +3,9 @@ class SitesController < ApplicationController # authenticate_user! ejecuta acción sólo si sesión existe before_filter :authenticate_user!,:except=> [:index,:show] + #filtro para contador de visitas + #after_filter :count_visit, :only => :show + # GET /sites # GET /sites.json def index @@ -88,4 +91,12 @@ def destroy format.json { head :no_content } end end + + private + + #definicion de la funcion contadora de visitas + #def count_visit + # @site.increment!(:visits) + #end + end diff --git a/app/models/comment.rb b/app/models/comment.rb index 5195ada..a2735e3 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -2,5 +2,8 @@ class Comment < ActiveRecord::Base belongs_to :site belongs_to :user - attr_protected :user_id, :site_id -end + #validaciones para evitar código malicioso -- longitud máxima 240 caracteres + validates :comment, :presence => true, :length => {:maximum => 240} + + attr_protected :user_id +end \ No newline at end of file diff --git a/app/models/site.rb b/app/models/site.rb index b9d0266..725ab28 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -4,5 +4,11 @@ class Site < ActiveRecord::Base has_many :comments + # validaciones para evitar código malicioso + #relativos a las coordenadas GPS ¿?¿? + #validates :name, :type_id, :latitude, :longitude, :zoom, :image_url, :presence => true + #validates :zoom, :numericality => {:greater_than_or_equal_to => 0.1} + validates :name, :presence => true + attr_protected :user_id end diff --git a/app/models/type.rb b/app/models/type.rb index 7c3d2ac..6c59f09 100644 --- a/app/models/type.rb +++ b/app/models/type.rb @@ -1,3 +1,7 @@ class Type < ActiveRecord::Base has_many :sites + + # validaciones para evitar código malicioso + validates :name, :description, :presence => true + validates :name, :uniqueness => true end diff --git a/app/models/user.rb b/app/models/user.rb index c3a8e3e..b8e5594 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -7,6 +7,9 @@ class User < ActiveRecord::Base has_many :sites has_many :comments + #validaciones para evitar código malicioso + validates :name, :presence => true + # Setup accessible (or protected) attributes for your model - attr_accessible :name,:email, :password, :password_confirmation, :remember_me + attr_accessible :name, :email, :password, :password_confirmation, :remember_me end diff --git a/app/views/comments/_form.html.erb b/app/views/comments/_form.html.erb index 3036a7c..d5857a7 100644 --- a/app/views/comments/_form.html.erb +++ b/app/views/comments/_form.html.erb @@ -12,16 +12,13 @@ <% end %>

- <%= f.label :comment %>
- <%= f.text_field :comment %> -
-
- <%= f.label :user_id %>
- <%= f.number_field :user_id %> + <%= f.label :Comment %>
+ <%= f.text_area :comment, :maxlength => 240, :rows => 7 %>
<%= f.label :site_id %>
- <%= f.number_field :site_id %> + <%= f.collection_select(:site_id, Site.find(:all,:order => :name), :id, :name) %> +
<%= f.submit %> diff --git a/app/views/comments/edit.html.erb b/app/views/comments/edit.html.erb index 3112283..fab3d96 100644 --- a/app/views/comments/edit.html.erb +++ b/app/views/comments/edit.html.erb @@ -1,12 +1,30 @@

Editing comment

<%= form_for(@comment) do |f| %> + <% if @comment.errors.any? %> +
+

<%= pluralize(@comment.errors.count, "error") %> prohibited this comment from being saved:

- <%= f.label :comment %>
- <%= f.text_area :comment, :characters=>240 %>
- -
<%= f.submit "Submit new comment" %>
+
    + <% @comment.errors.full_messages.each do |msg| %> +
  • <%= msg %>
  • + <% end %> +
+
+ <% end %> + +
+ <%= f.label :Comment %>
+ <%= f.text_area :comment, :maxlength => 240, :rows => 7 %> +
+
+ <%= f.label :site_id %>
+ <%= f.collection_select(:site_id, Site.find(:all,:order => :name), :id, :name) %> +
+
+ <%= f.submit %> +
<% end %> <%= link_to 'Show', @comment %> | -<%= link_to 'Back', comments_path %> +<%= link_to 'Back to site', site_path(@comment.site) %> diff --git a/app/views/comments/index.html.erb b/app/views/comments/index.html.erb index 60eeab4..a18c179 100644 --- a/app/views/comments/index.html.erb +++ b/app/views/comments/index.html.erb @@ -1,26 +1,30 @@ -

Listing comments

+
+

Listing comments

-
Comment UserComment Site
<%= comment.user.name %> <%= comment.comment %><%= comment.user_id %> <%= comment.site_id %> <%= link_to 'Show', comment %> <%= link_to 'Edit', edit_comment_path(comment) %>
- - - - - - - - -<% @comments.each do |comment| %> - - - - - - - - -<% end %> -
UserCommentSite
<%= comment.user.name %><%= comment.comment %><%= comment.site_id %><%= link_to 'Show', comment %><%= link_to 'Edit', edit_comment_path(comment) %><%= link_to 'Destroy', comment, confirm: 'Are you sure?', method: :delete %>
+ + <% @comments.each do |com| %> + + + + + + <% end %> +
+
+
<%= link_to com.user.name, com %>
+
<%= truncate(strip_tags(com.comment), :length => 240) %>
+
+
+ <%= link_to 'Show', com %>
+ <% if com.user == current_user %> + <%= link_to 'Edit', edit_comment_path(com) %>
+ <%= link_to 'Destroy', com, + :confirm => 'Are you sure?', + :method => :delete %> + <% end %> +
+
-<%= link_to 'New Comment', new_comment_path %> \ No newline at end of file +<%= link_to 'Back to Sites list', sites_path %> \ No newline at end of file diff --git a/app/views/comments/new.html.erb b/app/views/comments/new.html.erb index 9d37ba1..2605abf 100644 --- a/app/views/comments/new.html.erb +++ b/app/views/comments/new.html.erb @@ -1,11 +1,5 @@

New comment

-<%= form_for(@comment) do |f| %> +<%= render 'form' %> - <%= f.label :comment %>
- <%= f.text_area :comment, :characters=>240 %>
- -
<%= f.submit "Submit comment" %>
-<% end %> - -<%= link_to 'Back', comments_path %> +<%= link_to 'Back', site_comments_path %> \ No newline at end of file diff --git a/app/views/comments/show.html.erb b/app/views/comments/show.html.erb index 70a71e7..ad6bcc5 100644 --- a/app/views/comments/show.html.erb +++ b/app/views/comments/show.html.erb @@ -12,11 +12,11 @@

Site: - <%= @comment.site_id %> + <%= @comment.site_id %>

<% if @comment.user == current_user %> - <%= link_to 'Edit', edit_comment_path(@comment) %> | + <%= link_to 'Edit comment', edit_site_comment_path(@comment) %> | <% end %> -<%= link_to 'Back', comments_path %> +<%= link_to 'Back to site', site_path(@comment.site) %> \ No newline at end of file diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 4f9f37a..0cc716b 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -39,6 +39,17 @@
<%= yield %>
+ + + + <% if current_user %> + You had sign in as: <%= link_to current_user.name, edit_user_registration_path %> | + <%= link_to "Sign out", destroy_user_session_path, :method=>:delete %> + <% else %> + You must <%= link_to "Sign in", new_user_session_path %> for create and edit sites and comments + <%end %> + + + \ No newline at end of file diff --git a/app/views/sites/_form.html.erb b/app/views/sites/_form.html.erb index abc9fec..24c549d 100644 --- a/app/views/sites/_form.html.erb +++ b/app/views/sites/_form.html.erb @@ -17,12 +17,27 @@
<%= f.label :description %>
- <%= f.text_area :description , :rows => 4 %> + <%= f.text_area :description, :rows => 4 %>
<%= f.label :type_id %>
<%= f.collection_select(:type_id, Type.find(:all, :order => :name), :id, :name) %>
+ + +
<%= f.label :image_url %>
<%= f.text_field :image_url %> diff --git a/app/views/sites/edit.html.erb b/app/views/sites/edit.html.erb index d46384f..83144aa 100644 --- a/app/views/sites/edit.html.erb +++ b/app/views/sites/edit.html.erb @@ -3,4 +3,4 @@ <%= render 'form' %> <%= link_to 'Show', @site %> | -<%= link_to 'Back', sites_path %> +<%= link_to 'Back to Sites list', sites_path %> diff --git a/app/views/sites/index.html.erb b/app/views/sites/index.html.erb index 31f84d3..f4bc56c 100644 --- a/app/views/sites/index.html.erb +++ b/app/views/sites/index.html.erb @@ -14,9 +14,16 @@
<%= link_to site.name, site %>
<%= truncate(strip_tags(site.description), :length => 80) %>
+ +
+ <% if site.comments != [] %> + <%= link_to 'Comments', site_comments_path(site) %> + <% end %> - + +
+ <%= link_to 'Show', site %>
<% if site.user == current_user %> @@ -25,11 +32,6 @@ :confirm => 'Are you sure?', :method => :delete %> <% end %> - - - <% if site.comments %> - <%= link_to 'Comments', comments_path %>
- <% end %> <% end %> diff --git a/app/views/sites/new.html.erb b/app/views/sites/new.html.erb index 2988bdc..e241d2f 100644 --- a/app/views/sites/new.html.erb +++ b/app/views/sites/new.html.erb @@ -1,3 +1,25 @@ + +

New site

<%= render 'form' %> diff --git a/app/views/sites/show.html.erb b/app/views/sites/show.html.erb index 310b5ae..bd11cbf 100644 --- a/app/views/sites/show.html.erb +++ b/app/views/sites/show.html.erb @@ -11,13 +11,14 @@

Autor: <%= @site.user.name if @site.user %>

-

Comentarios: - <%= @site.comments if @site.comments %>

-

<% if @site.user == current_user %> - <%= link_to 'Edit', edit_site_path(@site) %> | + <%= link_to 'Edit site', edit_site_path(@site) %> | +<% end %> +<%= link_to 'Back to Sites list', sites_path %> | +<% if @site.comments != [] %> + <%= link_to 'Comments', site_comments_path(@site) %> | <% end %> -<%= link_to 'Back', sites_path %> +<%= link_to 'Add your comment', new_site_comment_path(@site) %> diff --git a/config/routes.rb b/config/routes.rb index 0f8693c..85a30d9 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,18 +1,19 @@ Planet::Application.routes.draw do + resources :comments + devise_for :users + resources :users get "types/ordered_index" # se añade una nueva ruta a la acción "ordered_index" - resources :sites do - resources :comments - end - - resources :comments - resources :types do # Rutas anidadas /types/id/sites..., resources :sites, :only => [ :index ] # Restringe a acción “index” end + + resources :sites do + resources :comments + end get "planet/index" From 422db90702507b6963ad8a8b63693f774620f22d Mon Sep 17 00:00:00 2001 From: danirubio Date: Wed, 18 Apr 2012 19:29:58 +0200 Subject: [PATCH 16/21] scaffold trip --- app/assets/javascripts/trips.js.coffee | 3 + app/assets/stylesheets/trips.css.scss | 3 + app/controllers/trips_controller.rb | 83 +++++++++++++++++++++++ app/helpers/trips_helper.rb | 2 + app/models/trip.rb | 2 + app/views/trips/_form.html.erb | 33 +++++++++ app/views/trips/edit.html.erb | 6 ++ app/views/trips/index.html.erb | 29 ++++++++ app/views/trips/new.html.erb | 5 ++ app/views/trips/show.html.erb | 25 +++++++ config/routes.rb | 2 + db/migrate/20120418172937_create_trips.rb | 12 ++++ test/fixtures/trips.yml | 13 ++++ test/functional/trips_controller_test.rb | 49 +++++++++++++ test/unit/helpers/trips_helper_test.rb | 4 ++ test/unit/trip_test.rb | 7 ++ 16 files changed, 278 insertions(+) create mode 100644 app/assets/javascripts/trips.js.coffee create mode 100644 app/assets/stylesheets/trips.css.scss create mode 100644 app/controllers/trips_controller.rb create mode 100644 app/helpers/trips_helper.rb create mode 100644 app/models/trip.rb create mode 100644 app/views/trips/_form.html.erb create mode 100644 app/views/trips/edit.html.erb create mode 100644 app/views/trips/index.html.erb create mode 100644 app/views/trips/new.html.erb create mode 100644 app/views/trips/show.html.erb create mode 100644 db/migrate/20120418172937_create_trips.rb create mode 100644 test/fixtures/trips.yml create mode 100644 test/functional/trips_controller_test.rb create mode 100644 test/unit/helpers/trips_helper_test.rb create mode 100644 test/unit/trip_test.rb diff --git a/app/assets/javascripts/trips.js.coffee b/app/assets/javascripts/trips.js.coffee new file mode 100644 index 0000000..7615679 --- /dev/null +++ b/app/assets/javascripts/trips.js.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ diff --git a/app/assets/stylesheets/trips.css.scss b/app/assets/stylesheets/trips.css.scss new file mode 100644 index 0000000..473cbc3 --- /dev/null +++ b/app/assets/stylesheets/trips.css.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the trips controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/controllers/trips_controller.rb b/app/controllers/trips_controller.rb new file mode 100644 index 0000000..c776169 --- /dev/null +++ b/app/controllers/trips_controller.rb @@ -0,0 +1,83 @@ +class TripsController < ApplicationController + # GET /trips + # GET /trips.json + def index + @trips = Trip.all + + respond_to do |format| + format.html # index.html.erb + format.json { render json: @trips } + end + end + + # GET /trips/1 + # GET /trips/1.json + def show + @trip = Trip.find(params[:id]) + + respond_to do |format| + format.html # show.html.erb + format.json { render json: @trip } + end + end + + # GET /trips/new + # GET /trips/new.json + def new + @trip = Trip.new + + respond_to do |format| + format.html # new.html.erb + format.json { render json: @trip } + end + end + + # GET /trips/1/edit + def edit + @trip = Trip.find(params[:id]) + end + + # POST /trips + # POST /trips.json + def create + @trip = Trip.new(params[:trip]) + + respond_to do |format| + if @trip.save + format.html { redirect_to @trip, notice: 'Trip was successfully created.' } + format.json { render json: @trip, status: :created, location: @trip } + else + format.html { render action: "new" } + format.json { render json: @trip.errors, status: :unprocessable_entity } + end + end + end + + # PUT /trips/1 + # PUT /trips/1.json + def update + @trip = Trip.find(params[:id]) + + respond_to do |format| + if @trip.update_attributes(params[:trip]) + format.html { redirect_to @trip, notice: 'Trip was successfully updated.' } + format.json { head :no_content } + else + format.html { render action: "edit" } + format.json { render json: @trip.errors, status: :unprocessable_entity } + end + end + end + + # DELETE /trips/1 + # DELETE /trips/1.json + def destroy + @trip = Trip.find(params[:id]) + @trip.destroy + + respond_to do |format| + format.html { redirect_to trips_url } + format.json { head :no_content } + end + end +end diff --git a/app/helpers/trips_helper.rb b/app/helpers/trips_helper.rb new file mode 100644 index 0000000..04f333d --- /dev/null +++ b/app/helpers/trips_helper.rb @@ -0,0 +1,2 @@ +module TripsHelper +end diff --git a/app/models/trip.rb b/app/models/trip.rb new file mode 100644 index 0000000..d079af4 --- /dev/null +++ b/app/models/trip.rb @@ -0,0 +1,2 @@ +class Trip < ActiveRecord::Base +end diff --git a/app/views/trips/_form.html.erb b/app/views/trips/_form.html.erb new file mode 100644 index 0000000..3f1ef01 --- /dev/null +++ b/app/views/trips/_form.html.erb @@ -0,0 +1,33 @@ +<%= form_for(@trip) do |f| %> + <% if @trip.errors.any? %> +

+

<%= pluralize(@trip.errors.count, "error") %> prohibited this trip from being saved:

+ +
    + <% @trip.errors.full_messages.each do |msg| %> +
  • <%= msg %>
  • + <% end %> +
+
+ <% end %> + +
+ <%= f.label :name %>
+ <%= f.text_field :name %> +
+
+ <%= f.label :description %>
+ <%= f.text_area :description %> +
+
+ <%= f.label :date %>
+ <%= f.date_select :date %> +
+
+ <%= f.label :user_id %>
+ <%= f.number_field :user_id %> +
+
+ <%= f.submit %> +
+<% end %> diff --git a/app/views/trips/edit.html.erb b/app/views/trips/edit.html.erb new file mode 100644 index 0000000..71287a4 --- /dev/null +++ b/app/views/trips/edit.html.erb @@ -0,0 +1,6 @@ +

Editing trip

+ +<%= render 'form' %> + +<%= link_to 'Show', @trip %> | +<%= link_to 'Back', trips_path %> diff --git a/app/views/trips/index.html.erb b/app/views/trips/index.html.erb new file mode 100644 index 0000000..47f649b --- /dev/null +++ b/app/views/trips/index.html.erb @@ -0,0 +1,29 @@ +

Listing trips

+ + + + + + + + + + + + +<% @trips.each do |trip| %> + + + + + + + + + +<% end %> +
NameDescriptionDateUser
<%= trip.name %><%= trip.description %><%= trip.date %><%= trip.user_id %><%= link_to 'Show', trip %><%= link_to 'Edit', edit_trip_path(trip) %><%= link_to 'Destroy', trip, confirm: 'Are you sure?', method: :delete %>
+ +
+ +<%= link_to 'New Trip', new_trip_path %> diff --git a/app/views/trips/new.html.erb b/app/views/trips/new.html.erb new file mode 100644 index 0000000..dd3e49d --- /dev/null +++ b/app/views/trips/new.html.erb @@ -0,0 +1,5 @@ +

New trip

+ +<%= render 'form' %> + +<%= link_to 'Back', trips_path %> diff --git a/app/views/trips/show.html.erb b/app/views/trips/show.html.erb new file mode 100644 index 0000000..f764047 --- /dev/null +++ b/app/views/trips/show.html.erb @@ -0,0 +1,25 @@ +

<%= notice %>

+ +

+ Name: + <%= @trip.name %> +

+ +

+ Description: + <%= @trip.description %> +

+ +

+ Date: + <%= @trip.date %> +

+ +

+ User: + <%= @trip.user_id %> +

+ + +<%= link_to 'Edit', edit_trip_path(@trip) %> | +<%= link_to 'Back', trips_path %> diff --git a/config/routes.rb b/config/routes.rb index 85a30d9..4f3d30a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,5 +1,7 @@ Planet::Application.routes.draw do + resources :trips + resources :comments devise_for :users diff --git a/db/migrate/20120418172937_create_trips.rb b/db/migrate/20120418172937_create_trips.rb new file mode 100644 index 0000000..9acf33c --- /dev/null +++ b/db/migrate/20120418172937_create_trips.rb @@ -0,0 +1,12 @@ +class CreateTrips < ActiveRecord::Migration + def change + create_table :trips do |t| + t.string :name + t.text :description + t.date :date + t.integer :user_id + + t.timestamps + end + end +end diff --git a/test/fixtures/trips.yml b/test/fixtures/trips.yml new file mode 100644 index 0000000..7e1227b --- /dev/null +++ b/test/fixtures/trips.yml @@ -0,0 +1,13 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html + +one: + name: MyString + description: MyText + date: 2012-04-18 + user_id: 1 + +two: + name: MyString + description: MyText + date: 2012-04-18 + user_id: 1 diff --git a/test/functional/trips_controller_test.rb b/test/functional/trips_controller_test.rb new file mode 100644 index 0000000..b09dce2 --- /dev/null +++ b/test/functional/trips_controller_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class TripsControllerTest < ActionController::TestCase + setup do + @trip = trips(:one) + end + + test "should get index" do + get :index + assert_response :success + assert_not_nil assigns(:trips) + end + + test "should get new" do + get :new + assert_response :success + end + + test "should create trip" do + assert_difference('Trip.count') do + post :create, trip: @trip.attributes + end + + assert_redirected_to trip_path(assigns(:trip)) + end + + test "should show trip" do + get :show, id: @trip + assert_response :success + end + + test "should get edit" do + get :edit, id: @trip + assert_response :success + end + + test "should update trip" do + put :update, id: @trip, trip: @trip.attributes + assert_redirected_to trip_path(assigns(:trip)) + end + + test "should destroy trip" do + assert_difference('Trip.count', -1) do + delete :destroy, id: @trip + end + + assert_redirected_to trips_path + end +end diff --git a/test/unit/helpers/trips_helper_test.rb b/test/unit/helpers/trips_helper_test.rb new file mode 100644 index 0000000..dcfddff --- /dev/null +++ b/test/unit/helpers/trips_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class TripsHelperTest < ActionView::TestCase +end diff --git a/test/unit/trip_test.rb b/test/unit/trip_test.rb new file mode 100644 index 0000000..1ed8ca6 --- /dev/null +++ b/test/unit/trip_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class TripTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end From 3665fa1e0fc271fca58bd8ccfbbabdc79591fad1 Mon Sep 17 00:00:00 2001 From: danirubio Date: Wed, 18 Apr 2012 19:31:00 +0200 Subject: [PATCH 17/21] migracion trip --- db/schema.rb | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/db/schema.rb b/db/schema.rb index 6dc94e8..caa9adb 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20120415184215) do +ActiveRecord::Schema.define(:version => 20120418172937) do create_table "comments", :force => true do |t| t.string "comment" @@ -31,6 +31,15 @@ t.integer "user_id" end + create_table "trips", :force => true do |t| + t.string "name" + t.text "description" + t.date "date" + t.integer "user_id" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + create_table "types", :force => true do |t| t.string "name" t.text "description" From b4f7b8145f064e1920ce930ef37b70eb49aa0f62 Mon Sep 17 00:00:00 2001 From: danirubio Date: Wed, 18 Apr 2012 20:20:37 +0200 Subject: [PATCH 18/21] mejorar vistas e incluir cleditor --- Gemfile | 2 + Gemfile.lock | 2 + app/assets/javascripts/application.js | 1 + app/assets/stylesheets/application.css | 1 + app/controllers/trips_controller.rb | 14 +++--- app/models/trip.rb | 3 ++ app/models/user.rb | 1 + app/views/layouts/application.html.erb | 5 ++- app/views/sites/index.html.erb | 3 +- app/views/trips/_form.html.erb | 4 -- app/views/trips/index.html.erb | 62 ++++++++++++++------------ app/views/trips/new.html.erb | 2 +- app/views/trips/show.html.erb | 13 +++--- app/views/types/index.html.erb | 40 ++++++++--------- app/views/types/ordered_index.html.erb | 50 +++++++++++---------- 15 files changed, 111 insertions(+), 92 deletions(-) diff --git a/Gemfile b/Gemfile index 7231379..fa40e6b 100644 --- a/Gemfile +++ b/Gemfile @@ -24,6 +24,8 @@ end gem 'jquery-rails' +gem 'cleditor_rails' + # To use ActiveModel has_secure_password # gem 'bcrypt-ruby', '~> 3.0.0' diff --git a/Gemfile.lock b/Gemfile.lock index 5730fc3..151e186 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -32,6 +32,7 @@ GEM bcrypt-ruby (3.0.1) bcrypt-ruby (3.0.1-x86-mingw32) builder (3.0.0) + cleditor_rails (0.0.3) coffee-rails (3.2.2) coffee-script (>= 2.2.0) railties (~> 3.2.0) @@ -115,6 +116,7 @@ PLATFORMS x86-mingw32 DEPENDENCIES + cleditor_rails coffee-rails (~> 3.2.1) devise jquery-rails diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 9097d83..84d87a2 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -11,5 +11,6 @@ // GO AFTER THE REQUIRES BELOW. // //= require jquery +//= require cleditor //= require jquery_ujs //= require_tree . diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index 3b5cc66..50d53e3 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -9,5 +9,6 @@ * compiled file, but it's generally better to create a new file per style scope. * *= require_self + *= require cleditor *= require_tree . */ diff --git a/app/controllers/trips_controller.rb b/app/controllers/trips_controller.rb index c776169..a764e65 100644 --- a/app/controllers/trips_controller.rb +++ b/app/controllers/trips_controller.rb @@ -1,4 +1,8 @@ class TripsController < ApplicationController + + # authenticate_user! ejecuta acción sólo si sesión existe + before_filter :authenticate_user!, :except => [ :index, :show ] + # GET /trips # GET /trips.json def index @@ -24,7 +28,7 @@ def show # GET /trips/new # GET /trips/new.json def new - @trip = Trip.new + @trip = current_user.trips.build # cambiar Trip.new por current_user.trips.build -- crea viaje vacio asociado a current user respond_to do |format| format.html # new.html.erb @@ -34,13 +38,13 @@ def new # GET /trips/1/edit def edit - @trip = Trip.find(params[:id]) + @trip = current_user.trips.find(params[:id]) # cambiar Trip por current_user.trips -- busca solo en sitios asociados a current_user end # POST /trips # POST /trips.json def create - @trip = Trip.new(params[:trip]) + @trip = current_user.trips.build(params[:trip]) # cambiar Trip.new por current_user.trips.build -- Asigna solo si sitio asociado a current_user respond_to do |format| if @trip.save @@ -56,7 +60,7 @@ def create # PUT /trips/1 # PUT /trips/1.json def update - @trip = Trip.find(params[:id]) + @trip = current_user.trips.find(params[:id]) # cambiar Trip por current_user.trips -- busca solo en sitios asociados a current_user respond_to do |format| if @trip.update_attributes(params[:trip]) @@ -72,7 +76,7 @@ def update # DELETE /trips/1 # DELETE /trips/1.json def destroy - @trip = Trip.find(params[:id]) + @trip = current_user.trips.find(params[:id]) # cambiar Trip por current_user.trips -- busca solo en sitios asociados a current_user @trip.destroy respond_to do |format| diff --git a/app/models/trip.rb b/app/models/trip.rb index d079af4..60bf07e 100644 --- a/app/models/trip.rb +++ b/app/models/trip.rb @@ -1,2 +1,5 @@ class Trip < ActiveRecord::Base + belongs_to :user + + attr_protected :user_id end diff --git a/app/models/user.rb b/app/models/user.rb index b8e5594..af96417 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -6,6 +6,7 @@ class User < ActiveRecord::Base has_many :sites has_many :comments + has_many :trips #validaciones para evitar código malicioso validates :name, :presence => true diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 0cc716b..9ff4924 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -6,6 +6,7 @@ <%= javascript_include_tag "application" %> <%= csrf_meta_tags %> +

New site

<%= render 'form' %> -<%= link_to 'Back', sites_path %> +<%= link_to 'Back to Sites list', sites_path %> diff --git a/app/views/sites/search.html.erb b/app/views/sites/search.html.erb new file mode 100644 index 0000000..36a5a86 --- /dev/null +++ b/app/views/sites/search.html.erb @@ -0,0 +1,39 @@ +
+

Listing Sites

+ + + <% @sites.each do |site| %> + + + + + + + + + <% end %> +
+ <%= link_to image_tag(site.image_url, :class => 'list_image'), site %> + +
+
<%= link_to site.name, site %>
+
<%= truncate(strip_tags(site.description), + :length => 80) %>
+
+
+ <%= link_to 'Show', site %>
+ <% if site.user == current_user %> + <%= link_to 'Edit', edit_site_path(site) %>
+ <%= link_to 'Destroy', site, + :confirm => 'Are you sure?', + :method => :delete %> + <% end %> + <% if !site.comments.empty? %> + <%= link_to 'Comments', site_comments_path(params[:site_id] = site.id) if site.comments %> + <% end %> +
+
+ +
+ +<%= link_to 'New site', new_site_path %> diff --git a/app/views/sites/show.html.erb b/app/views/sites/show.html.erb index 5208179..d95f62a 100644 --- a/app/views/sites/show.html.erb +++ b/app/views/sites/show.html.erb @@ -1,7 +1,39 @@ + + + +

<%= @site.type.name if @site.type %>

+
+ + <%= image_tag(@site.image_url, :class => 'site_image') %>

<%= @site.name %>

@@ -11,12 +43,12 @@

Autor: <%= @site.user.name if @site.user %>

-
+ -
-

Visitas: - <%= @site.visits %>

-
+
+

Visitas: + <%= @site.visits.length %>

+

diff --git a/app/views/trips/_trip.html.erb b/app/views/trips/_trip.html.erb index 6b83be8..a74c9f3 100644 --- a/app/views/trips/_trip.html.erb +++ b/app/views/trips/_trip.html.erb @@ -3,7 +3,7 @@ <% trip.visits.order(:hour).each do |visit| %> - <%= link_to image_tag(visit.site.image.url, :class => 'list_image'), visit.site %> + <%= link_to image_tag(visit.site.image_url, :class => 'list_image'), visit.site %> @@ -24,5 +24,5 @@ <% end %> - + \ No newline at end of file diff --git a/app/views/trips/edit.html.erb b/app/views/trips/edit.html.erb index 71287a4..d059df6 100644 --- a/app/views/trips/edit.html.erb +++ b/app/views/trips/edit.html.erb @@ -3,4 +3,4 @@ <%= render 'form' %> <%= link_to 'Show', @trip %> | -<%= link_to 'Back', trips_path %> +<%= link_to 'Back to Trips list', trips_path %> diff --git a/app/views/trips/show.html.erb b/app/views/trips/show.html.erb index 91c1693..05bef9d 100644 --- a/app/views/trips/show.html.erb +++ b/app/views/trips/show.html.erb @@ -25,21 +25,20 @@ <%= render(@trip) %> <% if @trip.user == current_user %> - <%= form_for(@visit, :remote => true) do |f| %> + <%= form_for(@visit, :remote => true) do |f| %> - - <% f.number_field :trip_id, :value => @trip.id, :hidden => true %> - <% f.collection_select(:site_id, Site.all, :id, :name) %> - <% f.select(:hour, Array.new(24,0).fill {|i| [(i.to_s + 'H'), i]}) %> - <% f.submit "Añadir sitio" %> - - <% end %> ---> <% end %> + <%= f.number_field :trip_id, :value => @trip.id, :hidden => true %> + <%= f.collection_select(:site_id, Site.all, :id, :name) %> + <%= f.select(:hour, Array.new(24,0).fill {|i| [(i.to_s + 'H'), i]}) %> + <%= f.submit "Añadir sitio" %> + <% end %> <% end %> + <% end %>
<% if @trip.user == current_user %> - <%= link_to 'Edit', edit_trip_path(@trip) %> + <%= link_to 'Edit', edit_trip_path(@trip) %> | <% end %> <%= link_to 'Back to Trips list', trips_path %> \ No newline at end of file diff --git a/app/views/visits/create.js.erb b/app/views/visits/create.js.erb new file mode 100644 index 0000000..d893e0f --- /dev/null +++ b/app/views/visits/create.js.erb @@ -0,0 +1,5 @@ +// Programa jQuery/Javascript +// -> sustituye la lista de visitas de un viaje en DOM +// -> HTML se genera en servidor con ERb + +$('#visit').html("<%= j render @visit.trip %>"); \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 4ef708a..a9ef522 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -18,6 +18,10 @@ resources :sites do resources :comments end + + resources :sites do + get 'search', :on => :collection + end get "planet/index" @@ -25,7 +29,7 @@ get "planet/ejemplo" - get "planet/author" # se añande una nueva ruta a la acción "author" + get "planet/author" # se añade una nueva ruta a la acción "author" # The priority is based upon order of creation: diff --git a/db/migrate/20120320100145_create_sites.rb b/db/migrate/20120320100145_create_sites.rb index 823209a..a6420df 100644 --- a/db/migrate/20120320100145_create_sites.rb +++ b/db/migrate/20120320100145_create_sites.rb @@ -4,6 +4,9 @@ def change t.string :name t.text :description t.integer :type_id + t.decimal :latitude, :precision => 8, :scale =>6 + t.decimal :longitude, :precision => 8, :scale =>6 + t.decimal :zoom, :precision => 8, :scale =>6 t.string :image_url t.timestamps diff --git a/db/seeds.rb b/db/seeds.rb index 99c1f6a..7e9ebfe 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -23,30 +23,45 @@ name: 'Pedriza', description: 'Magnifico valle al norte de Madrid en el Macizo Central', type_id: 2, - image_url: 'pedriza.png') + image_url: 'pedriza.png' + latitude: 40.751244, + longitude: -3.893069, + zoom: 1) Site.create( name: 'Catedral de Florencia', description: 'Catedral de la ciudad de Florencia con la que se inicia el Renacimiento', type_id: 1, - image_url: 'florencia.png') + image_url: 'florencia.png' + latitude: 43.783333, + longitude: 11.25, + zoom: 1) Site.create( name: 'Jardin de Lineo', description: 'Jardin de la ciudad sueca de Uppsala donde el famoso naturalista enia su coleccion de plantas', type_id: 2, - image_url: 'arbol1.png') + image_url: 'arbol1.png' + latitude: 59.862222, + longitude: 17.633889, + zoom: 1) Site.create( name: 'Reichstag', description: 'Parlamento aleman en la ciudad de Berlin', type_id: 1, - image_url: 'reichstag.png') + image_url: 'reichstag.png' + latitude: 52.5186, + longitude: 13.376, + zoom: 1) Site.create( name: 'Pergamo', description: 'Puerta del mercado de la antigua ciudad griega de Pergamo del museo arquelogico de Berlin', type_id: 3, - image_url: 'pergamo.png') + image_url: 'pergamo.png' + latitude: 52.521111, + longitude: 13.396667, + zoom: 1)