The end of the summer is here and RGSoC finished for our project. This was a very intensive experience. I have learned a lot and met very interesting people of the community.
I say thanks to Mathias @Geek_Force because we has helped me from the first moment.
Also to Benedikt @benediktdeicke who was always alert for our necessities. To Anika @langziehohr who offered me the use of the Travis offices because I didn't have a good place to meet my coach. Also thanks to the people of @travisci who has treated me so well.
Also thanks to each of you that has read my blog, encouraged me and gave me their opinions to improve my knowledge.
But this isn't the end. I continue learning Rails and working with it. So I'll continue writing and sharing in my new blog Adventures in Ruby Land.
See you in Ruby Land!
Freitag, 11. Oktober 2013
Sonntag, 29. September 2013
Cleaning code: Reducing the number of parameters in functions
This week I have continued refactoring the code in the application translate_german_words. After make smaller functions, I was able to see that there were a lot of parameters in the new functions, so I decided to create new classes. I moved some functionality from the principal script translate_words.rb to some new classes:
- read_words_from_file.rb
- search_words_in_dictionary.rb
- write_words_in_file.rb
I learned: 1 class <-> 1 responsability
Also, I created a config.yml file and with the class load_config.rb, load the configuration into the application.
Also, I removed not needed local variables in the methods, made the readme file more friendly and I got smaller methods.
I only can say that the process is so natural. I mean, you start using meaningful names, making smaller functions, creating classes..., step by step.
At the moment that's all!!
- read_words_from_file.rb
- search_words_in_dictionary.rb
- write_words_in_file.rb
I learned: 1 class <-> 1 responsability
Also, I created a config.yml file and with the class load_config.rb, load the configuration into the application.
Also, I removed not needed local variables in the methods, made the readme file more friendly and I got smaller methods.
I only can say that the process is so natural. I mean, you start using meaningful names, making smaller functions, creating classes..., step by step.
At the moment that's all!!
Mittwoch, 25. September 2013
Coding with glamour: Ruby style
Wow, what a week!
I assisted the Baruco conference and then the Monitorama Conference. Very interesting conferences!!
What I have done between conferences?
Speaking with @pedrotgimenez at Baruco about my code, he told me that my code in the application translate_german_words didn't follow the ruby style. Totally true. So, I decided apply Ruby Style Guide to my small application and I liked the result. I replaced some code lines with functions with meaningful names and I was able to remove comments.
After that, I installed the gem RubyCop to check if there was something else that I didn't make. There were some spaces at the end of lines. Also, the lines are very long. I'll check that later.
I assisted the Baruco conference and then the Monitorama Conference. Very interesting conferences!!
What I have done between conferences?
Speaking with @pedrotgimenez at Baruco about my code, he told me that my code in the application translate_german_words didn't follow the ruby style. Totally true. So, I decided apply Ruby Style Guide to my small application and I liked the result. I replaced some code lines with functions with meaningful names and I was able to remove comments.
After that, I installed the gem RubyCop to check if there was something else that I didn't make. There were some spaces at the end of lines. Also, the lines are very long. I'll check that later.
Freitag, 13. September 2013
Changing dinamically the terminal title in Mac using the rvm gemset name
I usually work with the Terminal on my Mac to run different commands, so I open different tabs, for example, one for voluntary, another for voluntary_classified_advertising and so on. Mathias suggested that it was a good idea to use a meaningful name as title of each terminal tab, so I can have the title "voluntary" if this terminal tab is in the directory "voluntary". To do that, you should open the Shell option in the Menu of Terminal, and select "Edit Title", and then change the Title.
However I thought: How I can make the title dinamically?
Well, when I change to the directory "voluntary", the gemspec is changed also. To do that I moved to my voluntary directory and executed:
rvm --create use --rvmrc ruby-1.9.3-p362@voluntary
So a .rvmrc file is created, and it changes the gemset for using ruby-1.9.3-p362@voluntary each time you move to "voluntary" directory.
Then, I wrote the script ~/bin/get_gemset.sh:
#!/bin/sh
DEFAULT_GEMSET="/Users/mcberros/.rvm/gems/ruby-1.9.3-p362"
GEMSET=`rvm gemset name`
if [ "$GEMSET" == "$DEFAULT_GEMSET" ]; then
echo 'default'
else
echo $GEMSET
fi
If you leave the voluntary directory and move to other directory without a specific gemset, then your gemset will be "default" and this will be the title of your terminal tab.
By the way, this weekend I am in the Baruco conference (http://www.baruco.org/) in the beautiful city of Barcelona.
Nice weekend!!!
However I thought: How I can make the title dinamically?
Well, when I change to the directory "voluntary", the gemspec is changed also. To do that I moved to my voluntary directory and executed:
rvm --create use --rvmrc ruby-1.9.3-p362@voluntary
So a .rvmrc file is created, and it changes the gemset for using ruby-1.9.3-p362@voluntary each time you move to "voluntary" directory.
Then, I wrote the script ~/bin/get_gemset.sh:
#!/bin/sh
DEFAULT_GEMSET="/Users/mcberros/.rvm/gems/ruby-1.9.3-p362"
GEMSET=`rvm gemset name`
if [ "$GEMSET" == "$DEFAULT_GEMSET" ]; then
echo 'default'
else
echo $GEMSET
fi
You must execute:
chmod u+x get_gemset.sh
Also, I modified my .bash_profile to add the following lines:
export PATH=~/bin:$PATH
PROMPT_COMMAND='echo -ne "\033]0;`get_gemset.sh`"; echo -ne "\007"'
Important: This line has to be the last in your .bash_profile:
[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm" # Load RVM into a shell session *as a function*
Then, reload your .bash_profile with the command:
source .bash_profile
By the way, this weekend I am in the Baruco conference (http://www.baruco.org/) in the beautiful city of Barcelona.
Nice weekend!!!
Mittwoch, 11. September 2013
Problems testing with Rspec
Since yesterday I have been working with Rspec reading and trying to follow the examples in the book "Instant RSpec Test-Driven Development How-to". I have some errors in the testing of validations of the Location model and in the create action in the controller. I'll continue learning Rspec to solve these problems.
Sonntag, 8. September 2013
The mistery of nested forms (III)
On last Friday, I read until the chapter "Writing ActiveRecord specifications" of the book "Instant RSpec Test-Driven Development How-to". I like this book because you can have a fast start for Rspec.
In the evening, Mathias solved some doubts that I had in the nested form view:
- The Task model is Mongo. I tried to use the method accepts_nested_attributes_for in this Model but it didn't work without has_many :vacancies. We didn't wanted this association, so I asked Mathias. The solution was that the Product::ClassifiedAdvertising::Task class in voluntary_classified_advertising implements the methods vacancies and vacancies_attributes=, so we don't need the method accepts_nested_attributes in our Task model to achieve the nested form between Task and Vacancy.
- Another doubt that I had is that the path to access the partial template "_vacancy_fields.html.erb" is "workflow/tasks/vacancy_fields". When I tried to access the partial template "_candidature_fields.html.erb" from "_vacancy_fields.html.erb", I had to use the path "products/types/classified_advertising/workflow/tasks/candidature_fields", although both templates are in the same directory. The solution is that we must implement a method "product" in candidature. This method allows to builds the relative path "products/types/classified_advertising/" for the partial template.
After that, I changed the view from a list of resources to a form for a resource, because what the client asked was a form and not a list. So an user can create a new Resource for an existing Vacancy. The problem is, as we saw in our last post, that Candidatures can't receive the attributes from Resources because there isn't a nested form between both Models. So we have to solve this problem the next day.
In the evening, Mathias solved some doubts that I had in the nested form view:
- The Task model is Mongo. I tried to use the method accepts_nested_attributes_for in this Model but it didn't work without has_many :vacancies. We didn't wanted this association, so I asked Mathias. The solution was that the Product::ClassifiedAdvertising::Task class in voluntary_classified_advertising implements the methods vacancies and vacancies_attributes=, so we don't need the method accepts_nested_attributes in our Task model to achieve the nested form between Task and Vacancy.
- Another doubt that I had is that the path to access the partial template "_vacancy_fields.html.erb" is "workflow/tasks/vacancy_fields". When I tried to access the partial template "_candidature_fields.html.erb" from "_vacancy_fields.html.erb", I had to use the path "products/types/classified_advertising/workflow/tasks/candidature_fields", although both templates are in the same directory. The solution is that we must implement a method "product" in candidature. This method allows to builds the relative path "products/types/classified_advertising/" for the partial template.
After that, I changed the view from a list of resources to a form for a resource, because what the client asked was a form and not a list. So an user can create a new Resource for an existing Vacancy. The problem is, as we saw in our last post, that Candidatures can't receive the attributes from Resources because there isn't a nested form between both Models. So we have to solve this problem the next day.
Freitag, 6. September 2013
The mistery of nested forms (II)
Last night, after my last post, I continued working because I wanted to complete the update controller. So I studied nested forms with polymorphy. I read code from other developers using nested and polymorphy. And I was able to see that I was making a mistake.
If we want nested forms we have to use the following structure:
(Parent object) has many (children objects)*
I thought our relation was:
Tasks > Many vacancies > Many Candidatures > Many Resources
However, studying our schema and models I was able to see that this relation wasn't right. In fact was:
Tasks > Many vacancies > Many Candidatures
Resource > Many Candidatures
So, we can't apply a nested form from Candidature to Resource, because the parent object is resource and not candidature.
After that, I removed the nested form for resource and wrote a modification in the update controller. If we push the 'Accept' button, we change the state of candidature to :accepted. If we push the 'Deny' button, we change the candidature state to :denied
I have now a view that works, although it isn't finished.
* It can be also a has-one relation, but in our case is a has-many relation
If we want nested forms we have to use the following structure:
(Parent object) has many (children objects)*
I thought our relation was:
Tasks > Many vacancies > Many Candidatures > Many Resources
However, studying our schema and models I was able to see that this relation wasn't right. In fact was:
Tasks > Many vacancies > Many Candidatures
Resource > Many Candidatures
So, we can't apply a nested form from Candidature to Resource, because the parent object is resource and not candidature.
After that, I removed the nested form for resource and wrote a modification in the update controller. If we push the 'Accept' button, we change the state of candidature to :accepted. If we push the 'Deny' button, we change the candidature state to :denied
I have now a view that works, although it isn't finished.
Donnerstag, 5. September 2013
The mistery of nested forms
Today I feel happy because I have learned a lot and also implemented a very difficult view without errors. Since yesterday I am implementing the nested form for the vacancy resource allocation through a candidatures casting.
First of all, I finally understood the different kinds of association for Active Records. After that, I was able to pass data between vacancies and candidatures.
Also, I was able to understand the nested form implementation and what happens between the involved models.
My next homework: implementation of the form's controller action.
More adventures tomorrow!
First of all, I finally understood the different kinds of association for Active Records. After that, I was able to pass data between vacancies and candidatures.
Also, I was able to understand the nested form implementation and what happens between the involved models.
My next homework: implementation of the form's controller action.
More adventures tomorrow!
Dienstag, 3. September 2013
Smaller functions and edit multiple elements in a table
Yesterday and today I started making smaller functions in the application translate_german_words. A consequence of using meaningful names is that you can make a function smaller creating new ones. Also is very helpful understand the different layers of abstraction in your application.
I could see that I was using the same parameter (word) in many new functions, so I changed this functions as methods of the class Word.
So at the moment I was able to see as a natural flow (easier to remember)
Meaningful Names > help making smaller functions > help guessing which function is a method of a class
Trying to make a function smaller I got blocked because there is a big "if" (similar to a case statement), so I'll have to think about it.
Also today I have learning how to edit multiple elements in a table. I should apply this new knowledge in the next task of Voluntary.
I could see that I was using the same parameter (word) in many new functions, so I changed this functions as methods of the class Word.
So at the moment I was able to see as a natural flow (easier to remember)
Meaningful Names > help making smaller functions > help guessing which function is a method of a class
Trying to make a function smaller I got blocked because there is a big "if" (similar to a case statement), so I'll have to think about it.
Also today I have learning how to edit multiple elements in a table. I should apply this new knowledge in the next task of Voluntary.
Sonntag, 1. September 2013
New model Asset
On Friday, Mathias and I created a new model Asset. In the last posts we did a refactoring for using a Resource (polymorphic) instead of User in Candidature and Vancancy models. A resource can be an User or an Asset.
Today I finished the "Meaningful Names" chapter of Clean Code. Then, solved an error in the application translate_german_words and finished the refactoring applying this chapter. At the moment, I can see three clear consequences of using meaningful names:
- A developer can read the code easier, like an story.
- You can see easier the repeated code.
- I guess, that it will be useful to make smaller functions or methods (next chapter)
My next task in Voluntary will be apply Edit multiple to create a nested resources table for each vacancy.
Also, I'll continue reading Clean Code and refactoring the application translate_german_words.
Mittwoch, 28. August 2013
Authorization with CanCan
I continued refactoring Voluntary to replace user by polymorphic resource association for vacancy and candidature models and got blocked when I tried to prove the refactoring in development mode so I had to wait for Mathias.
Meanwhile I continued working on my small application translate_german_words. It was about refactoring the part that saves the translation in a file. I only have one error and then this part is finished.
As Mathias arrived we found and handled the error source in a hidden authorization logic issue caused by the refactoring.
At this opportunity he explained to me the authorization solution CanCan.
We finished the refactoring and proved the integration of it by tests.
Positive things of the day:
Meanwhile I continued working on my small application translate_german_words. It was about refactoring the part that saves the translation in a file. I only have one error and then this part is finished.
As Mathias arrived we found and handled the error source in a hidden authorization logic issue caused by the refactoring.
At this opportunity he explained to me the authorization solution CanCan.
We finished the refactoring and proved the integration of it by tests.
Positive things of the day:
- Ran in circles with the block in Voluntary, but now I know much better the application
- Can see the importance of having tests. I don't have tests for my small application and I think the changes could be easier with the tests.
Dienstag, 27. August 2013
Tagging with Acts-as-Taggable-on
I have dedicated part of the day to learn about Tagging. I have used the gem Acts-as-Taggable-on in the project learning app. However, I didn't make the Tagging from Scratch.
Then, I continued refactoring my small application (translate_german_words). Another consequence of using meaningful names in your code is that you can see easily, where there is repetition in your code.
Bye!
Then, I continued refactoring my small application (translate_german_words). Another consequence of using meaningful names in your code is that you can see easily, where there is repetition in your code.
Bye!
Montag, 26. August 2013
Geocoder, clean code and refactoring
I've been learning Geocoder with Railscasts. We will need this gem for a story in the future. Also, I'll need to learn Google-Maps-for-Rails, but we'll have to investigate which free map can we use.
After that, I have read Clean Code (Use Intention-Revealing Names) and started to apply that in a small application (translate_german_words) that I wrote for translating a list of german words to spanish. It's difficult to give good names but I can see the results. When you read the code it's like you are reading a story.
I learned a pair of useful commands of git:
- To delete a lot of files that appear as deleted files in git status:
git rm $(git ls-files --deleted)
- To delete a file with Umlaut (for example: abhängig)
git rm $'third_version/first_traduction/GermanWordsTranslation_abha\314\210ngig_ADJ.ods'
After that, I worked in Voluntary. My task is refactoring the code to change from user_id to resource_id and resource_type. However I got blocked because I tried to test the application from voluntary_classified_advertising, and this application don't see the changes in Candidature table.
Tomorrow, I'll continue with Voluntary.
Bye!!
After that, I have read Clean Code (Use Intention-Revealing Names) and started to apply that in a small application (translate_german_words) that I wrote for translating a list of german words to spanish. It's difficult to give good names but I can see the results. When you read the code it's like you are reading a story.
I learned a pair of useful commands of git:
- To delete a lot of files that appear as deleted files in git status:
git rm $(git ls-files --deleted)
- To delete a file with Umlaut (for example: abhängig)
git rm $'third_version/first_traduction/GermanWordsTranslation_abha\314\210ngig_ADJ.ods'
After that, I worked in Voluntary. My task is refactoring the code to change from user_id to resource_id and resource_type. However I got blocked because I tried to test the application from voluntary_classified_advertising, and this application don't see the changes in Candidature table.
Tomorrow, I'll continue with Voluntary.
Bye!!
Freitag, 23. August 2013
A Roadblock and polymorphic Associations
To complete the current story about requesting all types of resources (e.g. human or material assets) as a project owner Mathias had to resolve a roadblock and implemented a own variant of accepts_nested_attributes_for magic for nested forms with different database systems (PostgreSQL and MongoDB).
After a break and joining interesting workshops and talks at Eurucamp we started the next story about responding resources as a crowd worker and so allocate a resource to a vacancy through a candidatures "casting".
In preparation of the story I followed the nested model form screencast and Mathias showed me how to override the wizard of the workspace in our new product voluntary_classified_advertising using the example of a new feature about replacing the core task result form by a resources form.
As the first task of the story I am refactoring the core vacancy and candidature to belong to a polymorphic resource (asset or user) instead of only an user and try to complete this task as a homework.
We'll review the homework at our next meet up at Travis office on Wednesday and start the next task about a new (material) model with the working title "asset" for the candidature's and vacancy's polymorphic resource association.
Have a nice weekend!
After a break and joining interesting workshops and talks at Eurucamp we started the next story about responding resources as a crowd worker and so allocate a resource to a vacancy through a candidatures "casting".
In preparation of the story I followed the nested model form screencast and Mathias showed me how to override the wizard of the workspace in our new product voluntary_classified_advertising using the example of a new feature about replacing the core task result form by a resources form.
As the first task of the story I am refactoring the core vacancy and candidature to belong to a polymorphic resource (asset or user) instead of only an user and try to complete this task as a homework.
We'll review the homework at our next meet up at Travis office on Wednesday and start the next task about a new (material) model with the working title "asset" for the candidature's and vacancy's polymorphic resource association.
Have a nice weekend!
Dienstag, 13. August 2013
Wicked and Redcarpet
Today I have learned Wicked with the Railscast for Wicked. For overriding the redirect_to_finish_wizard method, you should use a parameter.
def redirect_to_finish_wizard(options = nil)
redirect_to root_path , notice: "Thank you for signing up."
end
Then I used Redcarpet. The code for Redcarpet in Railscast for Draper don't work with my code (perhaps different versions), so I followed the documentation in Gem Redcarpet.
Today has been an easy day.
Montag, 12. August 2013
Remember and Reset Password and use of Draper
Today I have continued Remember and Reset Password. I achieved reset the password and the remember password in Sign Up and Log In pages. (The problem No route matches [PUT] "/password_resets.tyubOZQQExHjqqOSfMRqAw" was a silly typo error)
Also, very interesting. I use simple_for for the log_in form (I am not using an object for the model for the form, instead I am using the symbol :log_in)
<%= simple_form_for :log_in, { url: sessions_path } do |f| %>
<%= f.input :email %>
<%= f.input :password %>
<%= f.input :remember_me, as: :boolean, input_html: { checked: true } %>
<p><%= link_to "forgotten password?", new_password_reset_path %></p>
<%= f.button :submit, "Log in" %>
<% end %>
So, to use the params in the controller I needed to use params[:log_in]. An example:
user = User.authenticate(params[:log_in][:email], params[:log_in][:password])
After that, I followed the steps in Draper railscasts. I think that the version in the Railscasts is older than the one I used, because I had to make some changes.
Finally, I pushed every change in the repository.
Good night!!
Donnerstag, 8. August 2013
New product for voluntary
Today, we finished the creation of the new product voluntary_classified_advertising following the steps for creating a new voluntary product (engine). We created the model and data for this new model. Also, we talked about the briefing for the following stories in our backlog.
I learned a very interesting feature: The product has inside an engine for testing (called dummy), which can be used as a server, so we don't need an external application where voluntary and the products run.
Bye!!
I learned a very interesting feature: The product has inside an engine for testing (called dummy), which can be used as a server, so we don't need an external application where voluntary and the products run.
Bye!!
Montag, 5. August 2013
Underused features of ActiveRecord
Today, we have finished the story of adding an areas filter for projects in the worker scope.
To paginate database results, voluntary uses the gem will_paginate. As we needed a pagination for a mongodb collection, we figured out that the last release is not compatible with mongoid.
But we found this unreleased feature which supports it, so we now temporarily have to use the edge version of the gem.
While refactoring Mathias showed me one of the underused features of ActiveRecord: scope merging.
At the end of the day I started a new story about creating a new product voluntary_classified_advertising following the steps for creating a new voluntary product (engine).
Tomorrow we will extend the core task through the new product to support vacancy allocation.
More things tomorrow!!!
To paginate database results, voluntary uses the gem will_paginate. As we needed a pagination for a mongodb collection, we figured out that the last release is not compatible with mongoid.
But we found this unreleased feature which supports it, so we now temporarily have to use the edge version of the gem.
While refactoring Mathias showed me one of the underused features of ActiveRecord: scope merging.
At the end of the day I started a new story about creating a new product voluntary_classified_advertising following the steps for creating a new voluntary product (engine).
Tomorrow we will extend the core task through the new product to support vacancy allocation.
More things tomorrow!!!
Freitag, 2. August 2013
Refactoring & Patterns
Today, Mathias amplifies some previous lessons and the crowdsourcing vision needed to complete the story like refactoring, (design) patterns, routing, blocks and the engine to recommend proper work for the crowd.
Especially the refactoring of the routes file to use this gist and distribute concerns to separate route files was very interesting to me.
This prevents us from completing the story today but it was good to immerse myself in the software engineering principles and be more confident to live them in the future.
Have a nice weekend!
Especially the refactoring of the routes file to use this gist and distribute concerns to separate route files was very interesting to me.
This prevents us from completing the story today but it was good to immerse myself in the software engineering principles and be more confident to live them in the future.
Have a nice weekend!
Donnerstag, 1. August 2013
Remember Me & Reset Password
In http://disaster-assistance.blogspot.com/2013/07/how-i-test.html, I followed the railscast http://railscasts.com/episodes/275-how-i-test. Although I passed every test, my project_learning_app wasn't able to send a mail.
To solve the problem, instead of test environment, I used the development environment. So I used the following configuration in config/environments/development.rb, and it worked:
config.action_mailer.raise_delivery_errors = true
config.action_mailer.default_url_options = { host: "localhost:3000" }
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
address: 'smtp.gmail.com',
port: 587,
domain: 'localhost:3000',
user_name: 'user@gmail.com',
password: 'password',
authentication: 'plain',
enable_starttls_auto: true }
But, I had an error because I should complete the edit and update method of password_resets_controller.rb, so I followed another railscast: http://railscasts.com/episodes/274-remember-me-reset-password?view=asciicast
This railscast was interesting:
- First, the railscast use form_for and I use simple_for, so for the check_box in simpleform, I used:
<%= f.input :remember_me, as: :boolean, input_html: { checked: true } %>
- At the moment, I obtain the following error when I try to change the password:
No route matches [PUT] "/password_resets.tyubOZQQExHjqqOSfMRqAw"
Well, I'll continue with this interesting question another day.
Have a good weekend!!!
Abonnieren
Posts (Atom)