With Wednesday, Metis' career day behind us, we're finished with the course - but there's tons of resources we still have access to. However, we're now fully-fledged junior developers at this point.
It's been an incredible ride; and while I've said that several times throughout the blog, it still hasn't changed one bit. I've learned a lot, and we've been taught much. At the start, I only had what I gathered from my experiences in RMXP and video game modding, and now I can make full fledged web apps, the design principles to make them be powerful, flexible and lean, the various languages and tools to build them on and the drive and resources to move on.
It's wonderous what 3 months can achieve, and I really have gotten used to the idea of how what I have now is able to create things to help people with. I can express my creativity and my desire to help others or myself through what I've learned.
Creative writing is one of my favourite pastimes, and in that regard, I've found that coding isn't too different from it. In a sense, we are creating things - we are building something as a sort of creative need within us as builders. There's many ways to tell a story, or to paint a picture, or to write code that all convey or do the same thing. The processes that we go through and the challenges we face are all very similar to one another. We have to figure out how to overcome the hurdles of burn out, how to motivate ourselves, or those moments where we feel like we can't come up with anything valuable or something people would want, or times where we think we're weaker than our peers.
In that regard, coding requires the same dedication or passion as writing. I think that's why I've fallen in love with this particular art. While creative writing will be a pastime for me, I feel that it serves me best as my tool of self expression and introspection. Code, on the other hand, is my way to really create things for others. I have a lot of projects lined up that I think of daily as I ponder about family, friends and colleagues that could use my talents to make a few of their problems easier.
Definitely, now that I walk out of thoughtbot's office as a Metis graduate, I feel like I can code a lot more challenging apps, and these challenges are things I'd be glad to tackle.
Friday, 29 August 2014
Friday, 15 August 2014
Using Carrierwave and Fog
Following up installing RMagick in my previous post, I added Carrierwave and Fog. For the most part, instructions on getting Carrierwave running with Fog are in line with what I gathered in this blog post by JavaHabit. However, there's a few things to keep in mind:
Basically:
Add the dotenv-rails gem in your gemfile:
In your fog.rb file, trim it down as much as possible and make the key hashes point to an ENV.fetch of the keys you need:
In your .env file, make the following definitions for env variables:
In your gitignore file, add the uploads folder and .env to avoid uploading your images (if any) and secret keys onto github:
Lastly, in ImageUploader:
And that should set Fog up for your Carrierwave. Hope it helps!
- Once you get your fog.rb generated, be sure to move it to your config/initializers folder.
- If you plan on pushing your app to heroku, don't link your secret keys within the fog.rb file, you should install the dotenv-rails gem, make a .env file, put the keys inside it, then be sure to use ENV.fetch in the fog.rb file to obtain the keys remotely. Add .env to the gitignore file.
- Restart your server. Additionally, it's best to convert the hash syntax within the fog.rb file to the newer rails style (if you use version 4).
- Common error fixes: restart the server, remove the region line, and keep the fog.rb file to the bare minimum (delete mostlines to make most things set to their defaults). Those are the most common SO answers I've found.
Basically:
Add the dotenv-rails gem in your gemfile:
gem 'dotenv-rails'
In your fog.rb file, trim it down as much as possible and make the key hashes point to an ENV.fetch of the keys you need:
CarrierWave.configure do |config|
config.fog_credentials = {
provider: 'AWS',
aws_access_key_id: ENV.fetch("AWS_ACCESS_KEY_ID"),
aws_secret_access_key: ENV.fetch("AWS_SECRET_ACCESS_KEY"),
}
config.fog_directory = "bucketname"
config.fog_attributes = {"Cache-Control'=>'max-age=315576000"}
end
In your .env file, make the following definitions for env variables:
AWS_ACCESS_KEY_ID=accesskey
AWS_SECRET_ACCESS_KEY=secretaccesskey
In your gitignore file, add the uploads folder and .env to avoid uploading your images (if any) and secret keys onto github:
/public/uploads
.env
Lastly, in ImageUploader:
storage :fog
And that should set Fog up for your Carrierwave. Hope it helps!
Labels:
carrierwave,
coding,
fog,
gems,
Metis,
Programming,
ruby-on-rails
Wednesday, 13 August 2014
Installing RMagick on Windows
Today while working on our project, I was facing trouble installing RMagick. It was - as expected, a windows issue, and while most guides on troubleshooting were old and out of date, a more recent Stack Overflow response (January 2014) more or less pointed out the issue was that Windows might not be supported in the more recent versions of ImageMagick with RMagick. So the solution was to use older versions when it worked, and it definitely solved my issue in installing it.
To sum up and quote the answer by Dany Khalife:
And that's all there is to it. 'bundle install' should work just as well, too for the rails project. Hope this helps!
To sum up and quote the answer by Dany Khalife:
Uninstall ImageMagick and re-install a previous version that works with your Ruby setup.Keep in mind the version numbers! I'm running on Ruby 2.0.0 and it worked just fine. Be sure to use the following command, assuming ImageMagick was installed in C:/ :
This is what worked for me :
- Ruby 1.9.3
- Dev Kit 32-4.5.2
- ImageMagick 6.7.7 (i had a really hard time finding binary versions for legacy versions of ImageMagick so i guess this link will be handy for you: http://ftp.sunet.se/pub/multimedia/graphics/ImageMagick/binaries/)
- Rmagick 2.13.2
gem install rmagick --version=2.13.2 --platform=ruby -- --with-opt-lib=c:/ImageMagick/lib --with-opt-include=c:/ImageMagick/include
And that's all there is to it. 'bundle install' should work just as well, too for the rails project. Hope this helps!
Labels:
coding,
ImageMagick,
Programming,
Rmagick,
Ruby,
ruby-on-rails,
windows
Thursday, 17 July 2014
Writing Clean Code
Been awhile since my last post!
The last weeks have been refining our skill at using Ruby On Rails and going back to the basics. Most of this week has been about refining our codes and writing them cleanly, to make sure we have good conventions in terms of our writing code, and being able to go back and refactoring them.
This week we had 3 apps to practice writing clean code on. We had several sources to guide us this week.
First we had a video conference shown to us by Sandi Metz. She spoke about the design principles of SOLID object oriented code design; Very helpful to get a good foundation on how to start writing code. It aims to act as a guideline where to start writing the code and a set of principles to keep in mind.
On the second day we had a video from Aloha Ruby Con 2012 featuring Thoughtbot's Ben Orenstein speaking on refactoring from good to great. His talk highlights the importance of shifting methods to classes and minimizing the size of methods as much as possible. It's important to consider when your code can be shortened or refactored after you first make it. Methods should be written clearly and be as succinct as possible, and where variables are often repeated or passed around constantly it is usually best to shift the methods or variables to classes. That way, there are shorter classes, shorter methods and they are targeted and compartmentalized. This is an important concept to grasp to write clean code.
On Wednesday, we saw a talk by Avdi Grimm in Ruby Midwest 2011, speaking of confident code. The important message of the talk was that when writing code, we should 'tell, don't ask'. Code we right should have as little case statements and queries onto the properties of variables as much as possible, or else we run into the issue of 'timid code'. We need to adhere to duck typing - where we treat objects as what they are without having to ask what they are. This is exceptionally important with NilClasses, which is probably the most common cause for a query onto the class for the variable. In short, we should avoid 'if class == nil' statements, and simply handle NilClasses as if we expected them to come, or any other class that might come down our program. It's an important philosophy to grasp, where we own and understand our code. In the case of timid code, we would ask or approach the code carefully, which implies we don't understand or own the code we've written. or are reading.
Avdi's particular talk was very fascinating, and it was incredibly helpful in overcoming a programming challenge we had that day to query for hotels from a database, which I'll describe here. This particular blog post by Avdi describes the Null Object and their level of falsiness.
Between all these talks, we had a good grounding to stand on to start work on several programming challenges aimed at improving how we write code cleanly and how to refactor them after the fact, along with the process of handling pull requests.
For our programming challenge, we have to load up a CSV file that contains a table of various hotels/properties (I refer to them as properties, in case the list contains hotels, motels, inns, etc.), and the app will inquire the user for the name of a hotel they're looking for. It will print to the user details on the hotel if it is found, and when there is no property with a name they've written, it will tell the user no such property exists.
We have the main class, PropertyQuery which is what the user will be interacting most frequently. It takes in a properties variable on initialize, which should contain the table that should be read up by another class that returns the data. It is stored in the instance variable@properties . Afterwards, the instance of the class calls for the basic query process to be called in the method ask_user_for_query .
First, we'll look at how the class PropertyReader takes in and processes the table file. After the data is processed, it'll take the data and pass it to PropertyQuery.new as This is the .csv file:
Very simply, it has the hotel name, the city it's located in, the phone number, and the number of single or double rooms. This information needs to be passed into the PropertyReader class instance:
In this class, it takes in the file when an instance of PropertyReader is created and passes it to instance variable @file. It fills in @properties with new Property instances (see below) using the foreach method called with headers set to true as an option to take in the .csv file by row with the first row being for headers.
Each row is taken in as a hash with the headers being the keys, and the items in the rows being the values. Each row is a new instance of Property containing this key-value pair. While it is entirely possible to write up code to avoid using a new class altogether and creating individual hashes to fill @properties with instead, it's highly inefficient. We'd have to make explicit references to a specific hash shoveled into the @properties array or even worse call .each on it (which is very ineffective if the hash has a lot of records). Not to mention, we'd have to pull out the keys to obtain the values of particular item in the array we're looking for, and it makes it very difficult to read and conceptualize, and clogs up the code or class with so many additional methods and lines.
One of the things we learned during the 3 talks is that coders are often very timid or afraid to push their methods and code onto new classes. New classes actually make it very easy and saves up space (a huge plus) and improves readability, and enforces the tell, don't ask policy. We'll be able to take better grasp of our code by being able to define our own methods and properties onto our instances of classes. The thing about instance of classes is, they are very malleable. By shifting our thought process from simply compartmentalizing our code into single, large classes and onto classes as a collective, we're capable of confidently wielding the code we write as we see fit.
So to recap: we've made new instances of Property, which don't even need a variable name associated with them (a unique identifier based on object ID is created for every new instance). And these instances contain a hash of information (keys being the headers on the CSV file, values being the respective values associated to a single property like the name, city, etc.). These are all shoveled into an instance variable @properties within an instance of PropertyReader. Now, what can we do with these instances of Property? We want to be able to access their information, and by nature we can't access methods normally available to hashes when we have the instances outside the class (due to the hashes being in instances of Property). So how would we access them in another class' method? First, we define getter methods within Property, like so:
By having these methods on hand, we can call name on instances of Property to obtain the value of "Hotel", which is the name of the hotel. Or phone for the phone number of that Property instance. But recall that we are shoveling these instances into an instance variable within PropertyReader...
Which means that we'll need to be able to pass that array of instances containing a hash onto our main PropertyQuery class. For that reason, we call attr_reader on it to have a getter method we can use in our PropertyQuery:
Look at line 29-32 in particular. We load up a new instance of PropertyReader that takes in our .csv file, then it uses the command read_file on the instance to obtain and shovel the data into @properties within it; and then when we load up a new instance of PropertyQuery, we pass in property_reader.properties (a getter method we obtain when we used attr_reader on @properties). This gives us access to the array of instances of Property for use as our argument in PropertyQuery. Finally, on initialize, this gets passed into our instance variable @properties. Ultimately, this gets used in the method on line 24.
When this program is run and the data is loaded up into a PropertyQuery instance, the users are asked to put in the hotel name. Their query is passed into find_result, and their query is checked if it exists within our array of Property instances using .detect. With .detect, each item in the array is checked for a true condition and returns what was found. And here, with our instances we can use our defined .name method to obtain the value of the Hotel key in our instance. The first match is passed off as true and that will tell us we've found our hotel, returning that instance of Property. Earlier in the method definitions for PropertyQuery, the next step after query_for_property was to run .display, which is also a method for instances of Property to show all details for the property found.
However, note the || OR condition in the detect. Assuming there's no matches, then .detect will naturally return nil. But in this case, NullProperty.new is run in case the first half of the .detect command returns false, instead of just returning nil.
A timid programmer, as Avdi might define it would put an if statement to check if the return was nil. That's 3 lines at the minimum to check if @properties.detect returned Nil or NilClass! So what does NullProperty.new do in this case?
In short, this NullProperty class contains a method, display. Keep in mind that with instances of Property, we have a method for display too - but that does something vastly different. And PropertyQuery was written with the intention of doing .display following the find_result method was run - so no matter the result of @properties.detect, we'll always run .display on whatever we get - and instance of Property, or an instance of NullProperty.
This way, instead of going to ask and thus coming up with a case condition when we run into Nil in our query, we've managed to take control of Nil when it comes up (inevitably) in the user query. For that reason, the method find_result in PropertyQuery can only have one line.
By being able to use Class instances in this way we can be far more flexible and save a lot of lines. Our methods become far shorter and smaller, it becomes better to read (compared to the alternative we might've had to face), and it becomes less dependant on each other. By being less dependant, we're able to refactor this code if necessary without breaking another part of the code. This follows a fair bit of the Tell, don't ask philosophy and shows duck-typing - treating classes for what they are and not asking if they are of a particular class.
Next up in the exercise is to be able to use fuzzy searching with Regexp so we're able to find or suggest hotels that make partial matches in the name - in fact, remember the Zombies challenge I wrote about almost two months ago? The code is probably a bit of a mess, and it could definitely use a cleaner, effective rewrite - and now that I know about Regexp for fuzzy searching, I might even be able to cut down the code substantially to find matches or duplicate terms in the zombie dictionary...
I'm constantly reminded google searching, docs and other people are incredible help to find information and new tips. Videos, books and blogs are huge resources, and I really have grown to appreciate them.
So hopefully, this blog post comes up and helps you out somewhere down the line! Thanks for reading. :) Feel free to comment and let me know if there's a gap or something I misunderstood, too! I appreciate it.
Link to Git Repo: Here
The last weeks have been refining our skill at using Ruby On Rails and going back to the basics. Most of this week has been about refining our codes and writing them cleanly, to make sure we have good conventions in terms of our writing code, and being able to go back and refactoring them.
This week we had 3 apps to practice writing clean code on. We had several sources to guide us this week.
First we had a video conference shown to us by Sandi Metz. She spoke about the design principles of SOLID object oriented code design; Very helpful to get a good foundation on how to start writing code. It aims to act as a guideline where to start writing the code and a set of principles to keep in mind.
- Single Responsibility - no more than 1 reason for classes to change and the class should have only one responsibility
- Open/Close - modules should be open for extension but closed for modification
- Liskov Substitution - Objects should be substitutable by instances of its subclasses without affecting the program
- Interface Segregation - Don't make a class depend on methods its objects might not use, and specific interfaces are better than a single general purpose interface
- Dependency Inversion - Depend on abstractions, not concretions.High level modules shouldn't depend on low-level modules, and both should depend on abstractions.
On the second day we had a video from Aloha Ruby Con 2012 featuring Thoughtbot's Ben Orenstein speaking on refactoring from good to great. His talk highlights the importance of shifting methods to classes and minimizing the size of methods as much as possible. It's important to consider when your code can be shortened or refactored after you first make it. Methods should be written clearly and be as succinct as possible, and where variables are often repeated or passed around constantly it is usually best to shift the methods or variables to classes. That way, there are shorter classes, shorter methods and they are targeted and compartmentalized. This is an important concept to grasp to write clean code.
On Wednesday, we saw a talk by Avdi Grimm in Ruby Midwest 2011, speaking of confident code. The important message of the talk was that when writing code, we should 'tell, don't ask'. Code we right should have as little case statements and queries onto the properties of variables as much as possible, or else we run into the issue of 'timid code'. We need to adhere to duck typing - where we treat objects as what they are without having to ask what they are. This is exceptionally important with NilClasses, which is probably the most common cause for a query onto the class for the variable. In short, we should avoid 'if class == nil' statements, and simply handle NilClasses as if we expected them to come, or any other class that might come down our program. It's an important philosophy to grasp, where we own and understand our code. In the case of timid code, we would ask or approach the code carefully, which implies we don't understand or own the code we've written. or are reading.
Avdi's particular talk was very fascinating, and it was incredibly helpful in overcoming a programming challenge we had that day to query for hotels from a database, which I'll describe here. This particular blog post by Avdi describes the Null Object and their level of falsiness.
Between all these talks, we had a good grounding to stand on to start work on several programming challenges aimed at improving how we write code cleanly and how to refactor them after the fact, along with the process of handling pull requests.
For our programming challenge, we have to load up a CSV file that contains a table of various hotels/properties (I refer to them as properties, in case the list contains hotels, motels, inns, etc.), and the app will inquire the user for the name of a hotel they're looking for. It will print to the user details on the hotel if it is found, and when there is no property with a name they've written, it will tell the user no such property exists.
We have the main class, PropertyQuery which is what the user will be interacting most frequently. It takes in a properties variable on initialize, which should contain the table that should be read up by another class that returns the data. It is stored in the instance variable
First, we'll look at how the class PropertyReader takes in and processes the table file. After the data is processed, it'll take the data and pass it to PropertyQuery.new as This is the .csv file:
Very simply, it has the hotel name, the city it's located in, the phone number, and the number of single or double rooms. This information needs to be passed into the PropertyReader class instance:
Each row is taken in as a hash with the headers being the keys, and the items in the rows being the values. Each row is a new instance of Property containing this key-value pair. While it is entirely possible to write up code to avoid using a new class altogether and creating individual hashes to fill @properties with instead, it's highly inefficient. We'd have to make explicit references to a specific hash shoveled into the @properties array or even worse call .each on it (which is very ineffective if the hash has a lot of records). Not to mention, we'd have to pull out the keys to obtain the values of particular item in the array we're looking for, and it makes it very difficult to read and conceptualize, and clogs up the code or class with so many additional methods and lines.
One of the things we learned during the 3 talks is that coders are often very timid or afraid to push their methods and code onto new classes. New classes actually make it very easy and saves up space (a huge plus) and improves readability, and enforces the tell, don't ask policy. We'll be able to take better grasp of our code by being able to define our own methods and properties onto our instances of classes. The thing about instance of classes is, they are very malleable. By shifting our thought process from simply compartmentalizing our code into single, large classes and onto classes as a collective, we're capable of confidently wielding the code we write as we see fit.
So to recap: we've made new instances of Property, which don't even need a variable name associated with them (a unique identifier based on object ID is created for every new instance). And these instances contain a hash of information (keys being the headers on the CSV file, values being the respective values associated to a single property like the name, city, etc.). These are all shoveled into an instance variable @properties within an instance of PropertyReader. Now, what can we do with these instances of Property? We want to be able to access their information, and by nature we can't access methods normally available to hashes when we have the instances outside the class (due to the hashes being in instances of Property). So how would we access them in another class' method? First, we define getter methods within Property, like so:
By having these methods on hand, we can call name on instances of Property to obtain the value of "Hotel", which is the name of the hotel. Or phone for the phone number of that Property instance. But recall that we are shoveling these instances into an instance variable within PropertyReader...
Which means that we'll need to be able to pass that array of instances containing a hash onto our main PropertyQuery class. For that reason, we call attr_reader on it to have a getter method we can use in our PropertyQuery:
Look at line 29-32 in particular. We load up a new instance of PropertyReader that takes in our .csv file, then it uses the command read_file on the instance to obtain and shovel the data into @properties within it; and then when we load up a new instance of PropertyQuery, we pass in property_reader.properties (a getter method we obtain when we used attr_reader on @properties). This gives us access to the array of instances of Property for use as our argument in PropertyQuery. Finally, on initialize, this gets passed into our instance variable @properties. Ultimately, this gets used in the method on line 24.
When this program is run and the data is loaded up into a PropertyQuery instance, the users are asked to put in the hotel name. Their query is passed into find_result, and their query is checked if it exists within our array of Property instances using .detect. With .detect, each item in the array is checked for a true condition and returns what was found. And here, with our instances we can use our defined .name method to obtain the value of the Hotel key in our instance. The first match is passed off as true and that will tell us we've found our hotel, returning that instance of Property. Earlier in the method definitions for PropertyQuery, the next step after query_for_property was to run .display, which is also a method for instances of Property to show all details for the property found.
However, note the || OR condition in the detect. Assuming there's no matches, then .detect will naturally return nil. But in this case, NullProperty.new is run in case the first half of the .detect command returns false, instead of just returning nil.
A timid programmer, as Avdi might define it would put an if statement to check if the return was nil. That's 3 lines at the minimum to check if @properties.detect returned Nil or NilClass! So what does NullProperty.new do in this case?
In short, this NullProperty class contains a method, display. Keep in mind that with instances of Property, we have a method for display too - but that does something vastly different. And PropertyQuery was written with the intention of doing .display following the find_result method was run - so no matter the result of @properties.detect, we'll always run .display on whatever we get - and instance of Property, or an instance of NullProperty.
This way, instead of going to ask and thus coming up with a case condition when we run into Nil in our query, we've managed to take control of Nil when it comes up (inevitably) in the user query. For that reason, the method find_result in PropertyQuery can only have one line.
By being able to use Class instances in this way we can be far more flexible and save a lot of lines. Our methods become far shorter and smaller, it becomes better to read (compared to the alternative we might've had to face), and it becomes less dependant on each other. By being less dependant, we're able to refactor this code if necessary without breaking another part of the code. This follows a fair bit of the Tell, don't ask philosophy and shows duck-typing - treating classes for what they are and not asking if they are of a particular class.
Next up in the exercise is to be able to use fuzzy searching with Regexp so we're able to find or suggest hotels that make partial matches in the name - in fact, remember the Zombies challenge I wrote about almost two months ago? The code is probably a bit of a mess, and it could definitely use a cleaner, effective rewrite - and now that I know about Regexp for fuzzy searching, I might even be able to cut down the code substantially to find matches or duplicate terms in the zombie dictionary...
I'm constantly reminded google searching, docs and other people are incredible help to find information and new tips. Videos, books and blogs are huge resources, and I really have grown to appreciate them.
So hopefully, this blog post comes up and helps you out somewhere down the line! Thanks for reading. :) Feel free to comment and let me know if there's a gap or something I misunderstood, too! I appreciate it.
Link to Git Repo: Here
Monday, 7 July 2014
Foraying into JavaScript
Today begins the day where we learn JavaScript. My experiences with JavaScript are numerous, though how fruitful it is varies. At times, they go great. Othertimes, they don't. My biggest JavaScript run-ins are a somewhat-unfinished mod for Skyrim using the CreationKit's JavaScript-based papyrus, or when I tried to make Android apps. JavaScript is fairly difficult and compared to Ruby, a lot less 'face-value readable'.
So our first exercise in learning how to apply JavaScript to webpages is to make a very simple calculator and guessing game. Straightforward, very simple. And below are the notes I took as we were going through it as a class.
JavaScript gives us the power to make dynamic things happen on the client side. Where Rails and the Rails stack processes and renders views server-side, but java-script tells the user to render on the client. Browsers all accept JavaScript. ECMAScripts organize JavaScript and standardize it. It allows the user to interact with the Document Object Model, or the DOM. We can send smaller requests to the server via JavaScript instead of large chunks of whole views so it becomes more dynamic.
By default, a submitted form in HTML with no direction will send a get request to itself with the params. It won't actually send anything; but the params itself need to be obtained through the URL - which is the name field in the input tags:
<input type="number" name="left">
This will make a query-param get request with left having a value of what we had put in, with all params separated by ampersands:
/calculator.html?left=5&operator=*&right=3
--
HTML has a callback for forms, called onsubmit, which allows us to call javascript function. JavaScript functions can be passed around and will not run until called. Callbacks listen for events and will do an action when it happens. To prevent the forms from doing it's defalt behaviour for submit (as described abve - get request to itself), we can use return false in the onsubmit form.
To begin writing javascript in the html file, we can use <script> tags in the header.
To define a function in JavaScript, we define it with function:
function calculate() {
}
Where parameters are required, all functions must contain a param bracket (). All variables in the function need to be defined by 'var' then the name of the variable, and then to obtain params from the elements on the website we can call getElement on document. Specifically, we can getElementById (for example, our input type friend called left), thus:
var left = document.getElementById("left").value
But we have to make sure that we defined "left" as an ID in the form itself:
<input type="number" name="left" id="left">
In addition to being able to define and store param variables, we can also log them:
console.log(left)
When we do:
if (operator == "+") {
console.log(left + right);
}
We'll be adding the var left with var right. However, they might come out as strings:
log:
3 + 2
32
Which doesn't work for us. We have to typecast them (basically, turn them into integers in this case). Type casting in JScript basically parses in a parameter to a constructor and makes a number object:
var left = Number(document.getElementById("left").value;
And now we re-run the submit:
log:
3 + 2
5
If we wanted to do live debugging, we can put in a debugger statement:
<script>
function calculate(){
var left = Number(document.getElementById("left").value);
var right = Number(document.getElementById("right").value);
var operator = document.getElementById("operator").value;
debugger;
}
</script>
It will pause the script as it is running upon reaching the debugger. It allows us to debug whenever it makes a request for a parameter or call anything in that context. Very useful.
Javascript will allow us to append or add dynamically to the view. So if we want to display the results of our calculation. To where we want our calculation result:
<p>Result: <span id="result"></p>
We also have to make sure that we specify the variable and get the element by its ID:
var result = document.GetElementById("result");
And then we also have to allow the variable to change the value of a particular element in our calculation itself by calling innerHTML on the variable:
if (operator == "+") {
result.innerHTML = left + right
}
And that should do it!
Complete gist here .
So our first exercise in learning how to apply JavaScript to webpages is to make a very simple calculator and guessing game. Straightforward, very simple. And below are the notes I took as we were going through it as a class.
JavaScript gives us the power to make dynamic things happen on the client side. Where Rails and the Rails stack processes and renders views server-side, but java-script tells the user to render on the client. Browsers all accept JavaScript. ECMAScripts organize JavaScript and standardize it. It allows the user to interact with the Document Object Model, or the DOM. We can send smaller requests to the server via JavaScript instead of large chunks of whole views so it becomes more dynamic.
By default, a submitted form in HTML with no direction will send a get request to itself with the params. It won't actually send anything; but the params itself need to be obtained through the URL - which is the name field in the input tags:
<input type="number" name="left">
This will make a query-param get request with left having a value of what we had put in, with all params separated by ampersands:
/calculator.html?left=5&operator=*&right=3
--
HTML has a callback for forms, called onsubmit, which allows us to call javascript function. JavaScript functions can be passed around and will not run until called. Callbacks listen for events and will do an action when it happens. To prevent the forms from doing it's defalt behaviour for submit (as described abve - get request to itself), we can use return false in the onsubmit form.
To begin writing javascript in the html file, we can use <script> tags in the header.
To define a function in JavaScript, we define it with function:
function calculate() {
}
Where parameters are required, all functions must contain a param bracket (). All variables in the function need to be defined by 'var' then the name of the variable, and then to obtain params from the elements on the website we can call getElement on document. Specifically, we can getElementById (for example, our input type friend called left), thus:
var left = document.getElementById("left").value
But we have to make sure that we defined "left" as an ID in the form itself:
<input type="number" name="left" id="left">
In addition to being able to define and store param variables, we can also log them:
console.log(left)
When we do:
if (operator == "+") {
console.log(left + right);
}
We'll be adding the var left with var right. However, they might come out as strings:
log:
3 + 2
32
Which doesn't work for us. We have to typecast them (basically, turn them into integers in this case). Type casting in JScript basically parses in a parameter to a constructor and makes a number object:
var left = Number(document.getElementById("left").value;
And now we re-run the submit:
log:
3 + 2
5
If we wanted to do live debugging, we can put in a debugger statement:
<script>
function calculate(){
var left = Number(document.getElementById("left").value);
var right = Number(document.getElementById("right").value);
var operator = document.getElementById("operator").value;
debugger;
}
</script>
It will pause the script as it is running upon reaching the debugger. It allows us to debug whenever it makes a request for a parameter or call anything in that context. Very useful.
Javascript will allow us to append or add dynamically to the view. So if we want to display the results of our calculation. To where we want our calculation result:
<p>Result: <span id="result"></p>
We also have to make sure that we specify the variable and get the element by its ID:
var result = document.GetElementById("result");
And then we also have to allow the variable to change the value of a particular element in our calculation itself by calling innerHTML on the variable:
if (operator == "+") {
result.innerHTML = left + right
}
And that should do it!
Complete gist here .
Friday, 27 June 2014
A month of Metis
By the end of today, it will have been 4 weeks since I started learning at Metis. There's a lot that I've learned, and it's impressive when I think of how now I have the fundamentals to already build something great.
If there's something that really draws me into programming, it's that sense of creation you have at your fingertips. You can code together magnificent pieces of software, like how an artisan handles his craft - this is the builder of the tech era.
At Metis, broadly the four weeks covered the following:
One huge draw is the fact that programming is like a game, or a puzzle. There's many ways to solve these puzzles, and you learn that some ways are faster than others, while others are more effective or clean to look at. There's a bit of joy when I go back to old code I've written, see what I've done, grin and rewrite what I could've done better now that I'm a month into the study.
I wrote some code for the zombie dictionary a few weeks back, now, and maybe when I go back to it it'll be significantly different by the end.
That said, over the weekends I'm slowly working on getting to know Vim, and while it more or less functions similarly between Unix and Windows systems, the fundamental differences between them will take me some time to adjust - for example, we utilize Homebrew, Vundle, Thoughtbot's RCM, and dotfiles to handle and manage packages, bundles and configuration settings for Vim. With the exception of Vundle which has its own set of installations for Windows, everything else is made for a UNIX system in mind. However, I'm learning of several softwares that emulate similarly. For homebrew, I've learned of chocolatey ; and quick searches for dotfile installers and bundlers for windows have turned up a few that I still need to go through.
Given this, an important thing that I learned is the core differences in how OSX handles its system-wide installations compared to Windows (which uses environmental variables to set PATHs), and the inner workings of the dotfiles we've been installing. Ultimately, it helps me understand what is being changed 'under the hood' when we brew a bundle or run RCM. (Most of the dotfiles change internal settings in Vim, Git, RailsVim and TMux among many others).
Like I said, there will be a part two for that, so that should be coming following further dives into converting from Sublime Text to Vim.
If there's something that really draws me into programming, it's that sense of creation you have at your fingertips. You can code together magnificent pieces of software, like how an artisan handles his craft - this is the builder of the tech era.
At Metis, broadly the four weeks covered the following:
- HTML/CSS
- Ruby
- PostgreSQL
- Sinatra, irb
- Ruby on Rails
One huge draw is the fact that programming is like a game, or a puzzle. There's many ways to solve these puzzles, and you learn that some ways are faster than others, while others are more effective or clean to look at. There's a bit of joy when I go back to old code I've written, see what I've done, grin and rewrite what I could've done better now that I'm a month into the study.
I wrote some code for the zombie dictionary a few weeks back, now, and maybe when I go back to it it'll be significantly different by the end.
That said, over the weekends I'm slowly working on getting to know Vim, and while it more or less functions similarly between Unix and Windows systems, the fundamental differences between them will take me some time to adjust - for example, we utilize Homebrew, Vundle, Thoughtbot's RCM, and dotfiles to handle and manage packages, bundles and configuration settings for Vim. With the exception of Vundle which has its own set of installations for Windows, everything else is made for a UNIX system in mind. However, I'm learning of several softwares that emulate similarly. For homebrew, I've learned of chocolatey ; and quick searches for dotfile installers and bundlers for windows have turned up a few that I still need to go through.
Given this, an important thing that I learned is the core differences in how OSX handles its system-wide installations compared to Windows (which uses environmental variables to set PATHs), and the inner workings of the dotfiles we've been installing. Ultimately, it helps me understand what is being changed 'under the hood' when we brew a bundle or run RCM. (Most of the dotfiles change internal settings in Vim, Git, RailsVim and TMux among many others).
Like I said, there will be a part two for that, so that should be coming following further dives into converting from Sublime Text to Vim.
Labels:
coding,
Metis,
novice programming,
rails,
Ruby,
ruby-on-rails
Friday, 20 June 2014
Rails and Resources, Part 2
The all-important table! It's crucial this week that we have most of this table down, and honestly, I wish I wrote this blog post before our weekly quiz. Definitely would've helped!
Basically, each action here is a method defined in the table_controller.rb file (in this case, wombats). The paths are defined in the routes.rb file (under resources :wombats) in their most default state. Each path functions under a particular HTTP verb protocol. Using rails, we don't have to fully type a link in HTTP, but we can use rails code (link_to or form_for) to quickly make the connections between the records within the database (via the controller, that takes in the instances of said models with the corresponding tables based on the action used) and back within our html.erb file.The instance variable objects are basically stored references to particular database segments (such as the records we're looking for in Class.find(:id)), so when we link_to the instance variable, Rails already knows what and where we're referring to.
I know one of our classmates is working on a blogpost to fully describe the actions, so I'll be leaving this blogpost short and link to hers when she's finished.
Subscribe to:
Posts (Atom)