Hint: at the time of writing this (December 2021), 7.0 was the lastest version. You might also want to just try `gem install rails --no-doc` and install the latest version.
This guide is aimed at programming beginners who want to work with Ruby and Rails. If you’re a power user, skip to the end for the TL;DR section.
It assumes you’re on Windows 10 and have nothing pre-installed to work with Ruby and/or Rails, so this guide starts from scratch.
Go to the start menu and open Windows PowerShell
. It could also say (x86)
at the end, but be sure not to select the ISE
entry.
Now we check whether the winget
package manager is already installed. For this, type winget
into the PowerShell windows and hit Enter:
This probably looks like the image above. It prints out red text that tells you that winget
is not installed, so let’s install that first.
Type in:
exit
and hit Enter to close the PowerShell window now. If it does not show red text, but instead information about winget, then winget is already installed. In that case you can skip the installation and go directly installing packages.
To install winget
, we have to go to the pre-installed Microsoft Store.
There we need to install the App Installer by Microsoft.
By clicking the link, you should see a website that allows you to install the App Installer directly in the Microsoft Store. If it is already installed, make sure that you install the latest update before you continue.
Close the previous PowerShell window if it is still open.
Since you closed the previous PowerShell window, open a new window via the start menu.
Now enter the winget
command and hit Enter. You should see the following output:
This means winget was installed successfully. We’re now going to install the first bunch of packages, namely NodeJS, Yarn, Git, Ruby.
Copy and paste the following into PowerShell and hit Enter:
winget install OpenJS.NodeJS.LTS; winget install Yarn.Yarn; winget install Git.Git; `
winget install RubyInstallerTeam.RubyWithDevKit
You might get asked to accept the “msstore” source, which is the default Microsoft installation source. Type in “Y” and hit enter.
This will take a few minutes to install the packages. Small installation windows will pop up during this process and you’ll be asked to allow the installation of these packages like with any other installation. At the end it should look like this:
Now type in exit
(followed by Enter) to close the PowerShell window and re-open it again. Then enter the commands you see below:
All four commands should print out a version similar to the one seen here.
Now type in exit
(followed by Enter) to close the PowerShell window, as we have done before.
Now go to the Start menu and choose the “Start Command Prompt with Ruby”:
Enter this and hint enter:
ridk install 3
This will take a while and will show a lot of colorful output. At the end it should look like this:
After the installation succeeded, we can type exit
(followed by Enter) to close this window.
In the file explorer, create a folder called “rails” in your home folder. You can also give it a different name, but we will use “rails” here.
Now open a PowerShell window again, then enter cd
(the space afterwards is important!), drag the “rails” folder into the PowerShell window, drop it and then hit enter like this:
cd
here stands for “change directory”, we told PowerShell to navigate to this directory.
Copy and paste this into PowerShell and hit Enter:
gem install sqlite3
This might take a minute, it will print out a few lines, at the end it should say “1 gem installed”.
gem install rails --version "~> 7.0" --no-doc
This will produce a lot of output and install all of the rails dependencies. The second to last line should be “Successfully installed rails” including the Rails version number.
After that, enter:
rails new myapp
This also takes a few minutes, most probably longer than installing the packages. At the end, it should look like this:
If you see this, Rails has been successfully installed. We also created a small Rails application called myapp
.
You can now change to this app and start the Rails server:
cd myapp
followed by:
bundle exec rails server
You should copy and paste both commands and hit Enter for both.
It should now look like this:
This means the Rails server was started successfully. You can follow the instructions and open your Rails app in the browser by going to http://localhost:3000. You should see this:
Congratulations! You successfully installed Rails and created your first app.
To comfortably work with your Rails project, I recommend to install an editor. A popular editor is VS Code. You can install it via PowerShell:
winget install Microsoft.VisualStudioCode
After this, close and re-open the PowerShell window, navigate again to your rails
folder, then to your myapp
folder like we did in “Starting the Rails server”, then enter:
code .
Now VS Code starts and opens your myapp
project. You’re now ready to work on your app.
I hope this guide was helpful to you. Reach out via Twitter if you liked it and/or if you had any issues with it. Feel free to share it. Cheers!
For power users, the short summary:
winget
is installed, if not install or update App Installer from the Microsoft Store from herewinget install OpenJS.NodeJS.LTS; winget install Yarn.Yarn; winget install Git.Git; winget install RubyInstallerTeam.RubyWithDevKit
ridk install 3
gem install sqlite3; gem install rails --version "~> 7.0" --no-doc; rails new myapp
cd myapp; bundle exec rails server
This guide is aimed at programming beginners who want to work with Ruby and Rails. If you’re a power user, skip to the end for the TL;DR section.
It assumes you’re on Windows 10 and have nothing pre-installed to work with Ruby and/or Rails, so this guide starts from scratch.
Go to the start menu and open Windows PowerShell
. It could also say (x86)
at the end, but be sure not to select the ISE
entry.
Now we check whether the winget
package manager is already installed. For this, type winget
into the PowerShell windows and hit Enter:
This probably looks like the image above. It prints out red text that tells you that winget
is not installed, so let’s install that first. You should close the PowerShell window now. If it does not show red text, but instead information about winget, then winget is already installed. In that case you can skip the installation and go directly installing packages.
Go to https://github.com/microsoft/winget-cli/releases/latest and download the file that ends in .msixbundle
. Once it’s downloaded, double-click the file. It will ask you to “Update App Installer”, so you click the “Update” button. This should only take a few seconds and should show you a mostly white screen with the message: “For proper function of the app, try to launch a Windows app package”. This means you successfully installed the winget package manager and can close this window. Close the previous PowerShell window if it is still open.
Open the Windows PowerShell
as an administrator and hit “Yes” on the following User Account Control window:
Now enter the winget
command and hit Enter. You should see the following output:
This means winget was installed successfully. We’re now going to install the first bunch of packages, namely NodeJS, Yarn, Git, Ruby.
Copy and paste the following into PowerShell and hit Enter:
winget install node; winget install yarn; winget install git; `
winget install RubyInstallerTeam.RubyWithDevKit
This will take a few minutes to install the packages. Small installation windows will pop up during this process but you don’t have to do anything at this point. At the end it should look like this:
Now we have to close the PowerShell window and re-open it again as an administrator, as we have done before.
Enter this and hint enter:
ridk install 3
This takes a while, after it’s done we have to close the PowerShell window and re-open it again. This time you can open it by just clicking on the start menu entry, you don’t need to be an administrator.
Create a folder called “rails” in your home folder. You can also give it a different name, but we will use “rails” here. Then, go back to your PowerShell, enter “cd “ (the space afterwards is important!), drag the “rails” folder into the PowerShell window, drop it and then hit enter like this:
cd
here stands for “change directory”, we told PowerShell to navigate to this directory.
Copy and paste this into PowerShell and hit Enter:
gem install rails --version "~> 6.1" --no-doc
Hint: at the time of writing this (August 2021), 6.1 was the lastest version. You might also want to just try gem install rails --no-doc
and install the latest version.
After that, enter:
rails new myapp
This also takes a few minutes, most probably longer than installing the packages. At the end, it should look like this:
If you see this, Rails has been successfully installed. We also created a small Rails application called myapp
.
You can now change to this app and start the Rails server:
cd myapp
followed by:
bundle exec rails server
You should copy and paste both commands and hit Enter for both.
It should now look like this:
This means the Rails server was started successfully. You can follow the instructions and open your Rails app in the browser by going to http://localhost:3000. You should see this:
Congratulations! You successfully installed Rails and created your first app.
To comfortably work with your Rails project, I recommend to install an editor. A popular editor is VS Code. You can install it via PowerShell:
winget install vscode
After this, close and re-open the PowerShell window, navigate again to your rails
folder, then to your myapp
folder like we did in “Starting the Rails server”, then enter:
code .
Now VS Code starts and opens your myapp
project. You’re now ready to work on your app.
I hope this guide was helpful to you. Reach out via Twitter if you liked it and/or if you had any issues with it. Feel free to share it. Cheers!
For power users, the short summary:
winget
is installed, if not install the msixbundle from herewinget install node; winget install yarn; winget install git; winget install RubyInstallerTeam.RubyWithDevKit
ridk install 3
gem install rails --version "~> 6.1" --no-doc; rails new myapp
cd myapp; bundle exec rails server
⚠ UPDATE from 2021 ⚠
Installing Rails on Windows 10 got a lot easier. Follow my updated guide here.
As a coach for RailsGirls I had to assist in installing Rails on Windows recently. There’s an official guide, but even though it looks easy, it turns out to be a bit cumbersome to fully set up Rails and my goal was to make the process as easy and as fast as possible, without relying on RailsInstaller.
So what’ the goal here?
So let’s start!
This is the place where we enter all the following commands and it looks like this:
You can enter the command wmic os get OSArchitecture
and hit Enter, as seen in the screenshot:
PS C:\Users\YourName> wmic os get OSArchitecture
If this gives you 64-bit
, you should download The RubyInstaller that ends in x64
. If it says 32-bit
(which is unlikely), you should download RubyInstaller that ends in x86
. If unsure, use 64 bit (x64).
Create a new folder in your home directory and call it “railsgirls”. You could also give it a different name, but we will use this folder name from now on.
Then, download RubyInstaller, NodeJS and Yarn into the railsgirls folder. You could get these packages by hand and rename them to rubyinstaller.exe
, nodejs.msi
and yarn.msi
.
Optional: Instead of downloading the files by hand, you can run these commands (most probably only working in Windows 10):
wget https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.6.5-1/rubyinstaller-devkit-2.6.5-1-x64.exe -o rubyinstaller.exe
wget https://nodejs.org/dist/v12.13.0/node-v12.13.0-x64.msi -o nodejs.msi
wget https://yarnpkg.com/latest.msi -o yarn.msi
So now you have a railsgirls folder with these 3 files in them. Navigate to that folder in your PowerShell:
PS C:\Users\YourName> cd C:\Users\YourName\railsgirls
To not have to type the full folder path, you can enter cd
(don’t forget the space after cd!) and then drag and drop the folder from Explorer address bar as seen here:
Now, go to the Explorer folder (“railsgirls”) and create a new text file with a right-click > New > Text Document.
Rename the file install1.bat
and make sure that you remove the .txt
file extension from the suggested name.
Click yes when the following warning appears:
Right-click on this new install1.bat
file and select Edit:
You will now see and empty Notepad editor. Paste the following text into this window:
REM install1.bat
@echo off
If not exist rubyinstaller.exe (
echo ###########################################################################
echo #
echo # Could not find rubyinstaller.exe in this folder
echo # Get the latest version of Ruby+Devkit from https://rubyinstaller.org/ and
echo # rename the file to rubyinstaller.exe and put it into this folder.
echo
echo ###########################################################################
exit
)
If not exist nodejs.msi (
echo ###########################################################################
echo #
echo # Could not find nodejs.msi in this folder.
echo # Download NodeJS LTS from https://nodejs.org/en/ and
echo # rename the file to nodejs.msi and put it into this folder.
echo #
echo ###########################################################################
exit
)
If not exist yarn.msi (
echo ###########################################################################
echo #
echo # Could not find yarn.msi in this folder.
echo # Download Yarn stable from https://yarnpkg.com/ and
echo # rename the file to yarn.msi and put it into this folder.
echo #
echo ###########################################################################
exit
)
echo All files are present, continuing with installation...
echo Installing RubyInstaller...
.\rubyinstaller.exe /silent && ^
echo Installing NodeJS... && ^
.\nodejs.msi /passive && ^
echo Installing Yarn... && ^
.\yarn.msi /passive && ^
echo . && ^
echo . && ^
echo . && ^
echo ######################################### && ^
echo # NOW RUN INSTALL2.BAT # && ^
echo ######################################### && ^
pause
and now save this file. It should look like this:
After you saved this file, you can close Notepad.
Create a new file called install2.bat
exactly the same way (rename, remove .txt extension), with the following content:
REM install2.bat
@echo off
echo Installing MinGW... && ^
ridk install 3 && ^
echo Installing Bundler... && ^
gem install bundler --no-document && ^
echo Installing SQLite... && ^
gem install sqlite3 --platform=ruby --no-document && ^
echo Installing Rails... && ^
gem install rails --no-document && ^
echo Installing Setting up new rails app... && ^
rails new myapp && ^
echo . && ^
echo . && ^
echo . && ^
echo ######################################### && ^
echo # ALL DONE. # && ^
echo ######################################### && ^
pause
Also save this file and close Notepad.
Now back to your PowerShell. Type in ls
and hit Enter:
PS C:\Users\YourName\railsgirls> ls
You should see your two bat files and the three installers:
In your PowerShell, first, run .\install1.bat
:
PS C:\Users\YourName\railsgirls> .\install1.bat
This installs RubyInstaller, NodeJS and Yarn. You will see a few installer windows, they might prompt you for permission, other than that they should run by themselves.
At the end you will see:
#########################################
# NOW RUN INSTALL2.BAT #
#########################################
Press any key to continue . . .
Now, close this window and open a new PowerShell. Navigate to your railsgirls folder again (with cd
, as above).
PS C:\Users\YourName> cd C:\Users\YourName\railsgirls
Now run the .\install2.bat
script:
PS C:\Users\YourName\railsgirls> .\install2.bat
And the end you should see:
Webpacker successfully installed 🎉 🍰
.
.
.
#########################################
# ALL DONE. #
#########################################
Press any key to continue . . .
Nice! Now you installed Rails with all its dependencies, so you’re done. Congratulations!
The install2.bat
script created a new folder called myapp
with a Rails application in your railsgirls folder.
After you hit enter to exit the installer script, you can navigate to that Rails app with:
PS C:\Users\YourName\railsgirls> cd myapp
And inside that folder run:
PS C:\Users\YourName\railsgirls\myapp> bundle exec rails server
This might take 10 to 15 seconds, and should look like this:
PS C:\Users\YourName\railsgirls\myapp> bundle exec rails server
=> Booting Puma
=> Rails 6.0.1 application starting in development
=> Run `rails server --help` for more startup options
*** SIGUSR2 not implemented, signal based restart unavailable!
*** SIGUSR1 not implemented, signal based restart unavailable!
*** SIGHUP not implemented, signal based logs reopening unavailable!
Puma starting in single mode...
* Version 4.3.1 (ruby 2.6.5-p114), codename: Mysterious Traveller
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://[::1]:3000
* Listening on tcp://127.0.0.1:3000
Use Ctrl-C to stop
Go to your browser and enter: http://localhost:3000
and you should see this:
And that’s it!
If you found this installation guide helpful, share it with others. If you have any feedback, get in touch with me on Twitter.
Thanks!
]]>Ability
object. In the beginning, the test was quite fast, but the more rules we added, the longer it took to run the whole model test.
When we analyzed what was slowing down our test, we saw that quite some time is actually used persisting our models to the database with factory_girl as part of the test setup. It took a bit more than 60 seconds to run the whole ability spec, which is far too much for a model test.
Let’s look at an excerpt of our ability and its spec:
# ability.rb
def acceptance_modes
can [:read], AcceptanceMode
if @user.admin?
can [:create, :update], AcceptanceMode
can :destroy, AcceptanceMode do |acceptance_mode|
acceptance_mode.policies.empty?
end
end
end
# ability_spec.rb
describe Ability do
let!(:admin_user) { create(:admin_user) }
subject!(:ability) { Ability.new(admin_user) }
context 'acceptance mode' do
let!(:acceptance_mode) { create(:acceptance_mode) }
before(:each) do
create(:policy, :acceptance_mode => acceptance_mode)
end
[:read, :create, :update].each do |action|
it { should be_able_to(action, acceptance_mode) }
end
it { should_not be_able_to(:destroy, acceptance_mode) }
end
end
# ability_matcher.rb
module AbilityHelper
extend RSpec::Matchers::DSL
matcher :be_able_to do |action, object|
match do |ability|
ability.can?(action, object)
end
description do
"be able to #{action} -- #{object.class.name}"
end
failure_message do |ability|
"expected #{ability.class.name} to be able to #{action} -- #{object.class.name}"
end
failure_message_when_negated do |ability|
"expected #{ability.class.name} NOT to be able to #{action} -- #{object.class.name}"
end
end
end
RSpec.configure do |config|
config.include AbilityHelper
end
We first set up a user – in this case it’s an admin user – and then initialize our ability object with this user. We further have a model called AcceptanceMode
, which offers the usual CRUD operations. An acceptance mode has many policies. If any policy is attached to an acceptance mode, we don’t want to allow it to be deleted.
Note that a lot of models are created
, meaning these are persisted to the database. In this excerpt, we have 4 test cases. Each of these test cases needs to create the admin user, acceptance mode and also create a policy. This is a lot of persisted models, even more so if you realize that this is not all the acceptance mode specs and acceptance mode specs are only a small fraction of the whole ability spec. Other models are even more complex and require more tests for other dependencies.
But is this really necessary? Do we really need to persist the models or could we work with in-memory versions of these?
Let’s take a look at this modified spec:
describe Ability do
let(:stub_policy) { Policy.new }
let!(:admin_user) { build(:admin_user) }
subject!(:ability) { Ability.new(admin_user) }
context "acceptance mode" do
let(:acceptance_mode) { build(:acceptance_mode, :policies => [stub_policy]) }
[:read, :create, :update].each do |action|
it { should be_able_to(action, acceptance_mode) }
end
it { should_not be_able_to(:destroy, acceptance_mode) }
end
end
Note that all the create
calls are replaced with build
. We actually don’t need the models to be persisted to the database. The ability mainly checks if the user has admin rights (with admin?
), which can be tested with an in-memory version of a user. Further, the acceptance mode can be built with an array that contains an in-memory stub policy. If you look closely at the Ability
implementation, you will see that that’s not even necessary. Any object could reside in the array and the spec would still pass. But we decided to use an in-memory policy nonetheless.
With this approach, no model is persisted to the database. All models are in-memory but still collaborate the same way as they would have when loaded from the database first. However, no time is wasted on the database. The whole ability spec run time was reduced from 60 seconds to 5 seconds, by simply avoiding to persist models to the database in the test setup.
As an aside: there’s a lot of discussions around the topic of factories and fixtures. Fixtures load a fixed set of data into the database at the start of the test suite, which avoids these kinds of problems entirely.
That’s it. We hope you can re-visit some of your slow unit tests and try to use in-memory models, or avoid persisting your models for the next unit test you write!
]]>> user_ids = User.limit(5).pluck(:id)
(0.5ms) SELECT "users"."id" FROM "users" ORDER BY "users"."name" ASC LIMIT 5
=> [856, 857, 858, 850, 852]
Instead of calling map
on ActiveRecord objects, use pluck
if you only need a list of attributes. It avoids building ActiveRecord model objects and is a lot more efficient for larger collections.
> Post.where(:user_id => user_ids).count
(5.2ms) SELECT COUNT(* ) FROM "posts" WHERE "posts"."user_id" IN (856, 857, 858, 850, 852)
=> 286
You can provide an array argument for the where
clause, which is translated to an SQL IN
.
> Post.count
(0.6ms) SELECT COUNT(* ) FROM "posts"
=> 1120
> Post.where(:category => 'rails').count
(0.8ms) SELECT COUNT(* ) FROM "posts" WHERE "posts"."category" = 'rails'
=> 295
> Post.where.not(:category => 'rails').count
(0.9ms) SELECT COUNT(* ) FROM "posts" WHERE ("posts"."category" != 'rails')
=> 825
Using where.not
will test for inequality, where you might have used where('category != ?', 'rails')
in the past. This was introduced with Rails 4.0.
> date_start = Date.new(2013, 1, 1)
=> Tue, 01 Jan 2013
> date_end = Date.new(2013, 2, 1)
=> Fri, 01 Feb 2013
> puts Post.where(:published_on => date_start..date_end).to_sql
SELECT "posts".* FROM "posts" WHERE ("posts"."published_on" BETWEEN '2013-01-01' AND '2013-02-01')
Where clauses also support ranges. In the example above we see a ruby date range that gets elegantly translated
to SQL BETWEEN
syntax.
> puts Post.unscoped.order(:published_on => :asc).to_sql
SELECT "posts".* FROM "posts" ORDER BY "posts"."published_on" ASC
=> nil
> puts Post.unscoped.order(:published_on => :desc).to_sql
SELECT "posts".* FROM "posts" ORDER BY "posts"."published_on" DESC
=> nil
Instead of the using the order
argument with a string as order("published_on DESC")
, you can simply pass a hash.
> puts Post.unscoped.order(:published_on => :desc).except(:order).to_sql
SELECT "posts".* FROM "posts"
With the expect
syntax you can get rid of clauses to the ActiveRecord relation that were added before. This could
come in handy if you’re given a base scope that is valid for all cases except yours and avoids throwing away any other modifications to the relation.
> Post.none.where(:category => "rails")
=> []
This feature might look like non-sense at first. The none
clause makes sure that whatever clause is added to the relation, the result will always be empty. Again, this might make sense if you are provided with a relation and have to return one again. Say now we have a case where the current query is not valid due to permission constraints. Adding the none
clause makes sure that whatever relation modification follows, the final query will not hit the database and will be empty.
post = Post.readonly.first
post.title = "Don't change me!"
post.save!
The readonly
clause makes sure that a relation cannot be modified. This might make sense if you pass an object to any code that is not yours (e.g. a library) and want to make sure that the object is not modified.
So that’s it. I hope you can use some of these tricks to not only make your code faster and more elegant, but also more readable.
]]>This is where the tools:
prefix comes in handy!
<TextView
android:id="@+id/someLabel"
style="@style/Text.Label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="@string/some_string"
/>
<ListView
android:id="@+id/someList"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:listitem="@android:layout/simple_list_item_2"
/>
In the first text view you can see a text attribute (tools:text
) that is only visible in the layout designer. This way, you
can provide a sample text that will render nicely in the designer, but not accidentally expose sample texts in your actual application.
In the list view, the tools:listitem
directive specifies a layout which the list view items should use. This way, your list views are pre-filled with sample items in the designer. If you also use the tools
directives in your list item layout, the pre-filled items will use them as well.
You can use almost any android
attribute and replace it with tools
to have design-time attributes. In fact, if you provide attributes with both prefixes, the tools
prefix is valid during design-time, while your actual android
attribute is used during runtime.
You can find more information in the official documentation.
]]>