Am I logically reiterating the same code block in Ruby? - ruby

What is the difference between these two lines of Ruby code?
if params.values.any? { |value| value == "" }
and
#post = current_user.posts.build(title: params[:post][:title], content: params[:post][:content])
The contexts in which they are used are as follows, respectively:
post '/builds' do
redirect_if_not_logged_in
if params.values.any? {|value| value == ""}
erb :'builds/new', #locals: {message: "Unable to Continue!"}
else
user = User.find(session[:user_id])
#build = Build.create(title: params[:title], budget: params[:budget], user_id: params[:user.id])
redirect to "/builds/#{#build.id}"
end
end
and
post "/builds" do
redirect_if_not_logged_in
#build = current_user.builds.build(title: params[:post][:title], content: params[:build][:content])
if #build.save
redirect "/builds"
else
erb :"/builds/new.html"
end
end

if params.values.any? {|value| value == ""}
erb :'builds/new', #locals: {message: "Unable to Continue!"}
What you're doing here is returning an error message if any of the parameter values are empty. This can happen if the user didn't fill out one of the form fields on the page.
#post = current_user.posts.build(title: params[:post][:title], content: params[:post][:content])
This creates a new post object using the given parameters. If you didn't have that first code block, this might possibly set one of the values to an empty string ("").
There are other ways to do this (specifically, model-level validations), but hopefully that helps you figure out what's going on here.

Related

Having issues writing my block, SYNTAX ERROR?

if you need my to post other info i will!
but i believe this is just syntax?
not sure if it is wrong but i believe its written correctly.
SyntaxError: /Users/cod3/carbuilds/app/controllers/builds_controller.rb:21: syntax error, unexpected else else ^~~~ /Users/cod3/carbuilds/app/controllers/builds_controller.rb:34: syntax error, unexpected end end ^~~ /Users/cod3/carbuilds/app/controllers/builds_controller.rb:94: syntax error, unexpected end-of-input, expecting end
this is my block code where its saying i am having the syntax error but i think its all right ,
correct me if i am wrong
class BuildsController < ApplicationController
get '/builds' do
if logged_in?
#builds = Build.all
erb :'builds/index'
else
erb :'users/login' #locals: {message: "Unable to Continue please login"}
end
end
get "/builds/new" do
redirect_if_not_logged_in
#build = Build.new
erb :"/builds/new"
end
post '/builds' do
redirect_if_not_logged_in
if params.values.any? {|value| value == ""}
erb :'builds/new', #locals: {message: "Unable to Continue!"}
else
user = User.find(session[:user_id])
#build = Build.create(title: params[:title], budget: params[:budget], user_id: params[:user.id])
redirect to "/builds/#{#build.id}"
end
end
get 'builds/:id' do
if logged_in?
#build = Build.find(params[:id])
erb :'builds/show'
else
erb :'users/login', #locals: {message: "Access Denied"}
end
end
get 'builds/:id/edit' do
if logged_in?
#build = Build.find(params[:id])
erb :'builds/edit'
else
erb :'users/login' #locals: {message: "Access Denied"}
end
end
patch '/builds/:id' do
if params.values.any? {|value| value == ""}
 #build = Build.find(params[:id])
erb :'builds/edit', locals: {message: "You're missing information"}
redirect to "/builds/#{params[:id]}/edit"
else
#build = Build.find(params[:id])
#build.title = params[:title]
#build.budget = params[:budget]
#build.save
redirect to "/builds/#{#build.id}"
 end
end
 delete '/builds/:id/delete' do
#build = build.find(params[:id])
if session[:user_id]
#build = Build.find(params[:id])
if #build.user_id == session[:user_id]
#build.delete
redirect to '/builds'
else
redirect to '/builds'
end
else
redirect to '/login'
end
end
private
def set_build
#build = build.find_by_id(params[:id])
if #build.nil?
flash[:error] = "Couldn't find a build with id: #{params[:id]}"
redirect "/builds"
end
end
def redirect_if_not_authorized
redirect_if_not_logged_in
if !authorize_build(#build)
flash[:error] = "You don't have permission to do that action"
redirect "/builds"
end
end
end
end
this is my entire BuildsController file. Im creating a build a CAR BUILD app and it given me these syntax errors. If you have time i'd love to share it all with you so that you can see what i am doing. It is a big project but so far im down to just syntax so thats a good thing.
There's an extra trailing comma in this line:
erb :'users/login', #locals: {message: "Access Denied"}
# ^ here
You probably have one too many closing ends at the end of the file.
You have incorrect block indentation in several places. Fix them, and it will be much easier to catch/avoid these issues altogether. A properly setup editor will even automate indentation formatting for you.
Sure, it is "just" syntax, but the syntax is important, as invalid syntax is unclear. The computer isn't going to guess what your intention was, so it means your code is effectively meaningless.
For example, a math syntax typo makes it impossible to definitively interpret:
(3 + 2 * 5
That expression could possibly mean any of:
(3) + 2 * 5 - possible missing ) location
(3 + 2) * 5 - possible missing ) location
(3 + 2 * 5) - possible missing ) location
3 + 2 * 5 - possible extra (
An example of unclear syntax in English that renders a sentence ambiguous (and thus factually meaningless):

how can i use rspec correctly?

My code creates a github gist using the github API. After creating the gist, the API returns a status code to me. If the code is "201" the gist was created. But if it is "400" there was an error. In my code the variable that saves that state is response_status
This is my code:
require 'net/http'
require 'json'
require 'uri'
class Gist
attr_reader :response_status
attr_reader :try_again
def initialize(filename,description,state,content)
#filename = filename
#description = description
#state = state
#content = content
end
def post(uri, request)
request.basic_auth("my_username", "my_token")
request.body = JSON.dump({
"description" => #description,
"public" => #state,
"files" => {
#filename => {
"content" => #content
}
}
})
req_options = { use_ssl: uri.scheme == "https" }
begin
response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
http.request(request)
end
json = response.body
parsed = JSON.parse(json)
#response_status = "#{ response.code }"
if #response_status == "201"
puts "Tu gist se ha creado con exito. La URL de su gist es: "+ parsed["url"]
end
rescue SocketError => se
puts "Ha ocurrido un error de conexión. Quiere intentar nuevamente?"
#try_again = gets.chomp.capitalize
end
end
end
loop do
filename= gets.chomp
if File.exist?("#{filename}")
description = gets.chomp
state = gets.chomp.capitalize
if state == "Si"
state = true;
elsif state == "No"
state = false;
end
open(filename, "r") { |file| #contenido = file.read() }
content = #contenido
uri = URI.parse("https://api.github.com/gists")
request = Net::HTTP::Post.new(uri)
gist = Gist.new(filename,description,state,content)
gist.post(uri, request)
break if gist.response_status == "201"
break if gist.try_again == "No"
else
puts "The file does not exist"
continue = gets.chomp.capitalize
break if continue == "No"
end
end
I want to test test cases using rspec, but I did not understand.
It occurred to me as a test case that a Gist be created. For example, I thought about checking if the variable that returns the state of the Gist is equal to "201", but that didn't work for me.
This is my rspec file:
require './git_clases.rb'
RSpec.describe Gist do
describe "#Gist" do
it "#Gist created" do
expect(response_status)==("201")
end
end
end
response_status is a method on your Gist object. You need to create a Gist object, call post on it, and check response_status on your object.
RSpec.describe Gist do
# Generally organize by method
describe "#post" do
# Example descriptions read grammatically correct
# "Gist #post creates a gist"
it "creates a gist" do
filename = "test.txt"
description = "testing gist"
state = "dunno what goes here"
content = "some test content"
gist = described_class.new(filename, description, state, content)
uri = URI.parse("https://api.github.com/gists")
request = Net::HTTP::Post.new(uri)
gist.post(uri, request)
expect(gist.response_status).to eq 201
end
end
end
described_class is Gist from RSpec.describe Gist. It's preferable to hard coding the class name into the example in case that example becomes shared or the class name changes.
expect(gist.response_status).to eq 201 is really expect(gist.response_status).to( eq(201) ). This compares gist.response_status using the matcher eq(201) which just checks that it equals 201. This might seem a bit much for a simple equality check, but it allows rspec to provide a wide variety of complex matchers as well as custom ones.
Your post method is a bit odd in that the user is expected to initialize and pass in the URL and Request object. That should probably be done by Gist.
There is no need to turn the response_status into a string. It's preferable to leave it as an Integer. If you do need it as a string, use response.code.to_s.

Ruby If statement

I am trying to do a post and run some if statement. What I want to do is:
check all fields are filled
if all fields are filled move on to next step, or else reload page
check if already in data base
add if not already in data base
post "/movies/new" do
title = params[:title]
year = params[:year]
gross = params[:gross]
poster = params[:poster]
trailer = params[:trailer]
if title && year && gross && poster && trailer
movie = Movie.find_by(title: title, year: year, gross: gross)
if movie
redirect "/movies/#{movie.id}"
else
movie = Movie.new(title: title, year: year, gross: gross, poster: poster, trailer: trailer)
if movie.save
redirect "/movies/#{movie.id}"
else
erb :'movies/new'
end
end
else
erb :'movies/new'
end
end
I don't think my if statement is correct. It works even if all my fields are not filled
Your code is doing a lot of work in one single method. I would suggest to restructure it into smaller chunks to make it easier to manage. I mostly code for Rails, so apologies if parts of these do not apply to your framework.
post "/movies/new" do
movie = find_movie || create_movie
if movie
redirect "/movies/#{movie.id}"
else
erb :'movies/new'
end
end
def find_movie
# guard condition to ensure that the required parameters are there
required_params = [:title, :year, :gross]
return nil unless params_present?(required_params)
Movie.find_by(params_from_keys(required_params))
end
def create_movie
required_params = [:title, :year, :gross, :poster, :trailer]
return nil unless params_present?(required_params)
movie = Movie.new(params_from_keys(required_params))
movie.save ? movie : nil # only return the movie if it is successfully saved
end
# utility method to check whether all provided params are present
def params_present?(keys)
keys.each {|key| return false if params[key].blank? }
true
end
# utility method to convert params into the hash format required to create / find a record
def params_from_keys(keys)
paras = {}
keys.each { |key| paras.merge!(key: params[key]) }
paras
end
Even if you type nothing in the HTML fields, they will still be submitted as empty strings.
You can avoid having empty parameters by, for example, filtering them:
post '/movies/new' do
params.reject! { |key, value| value.empty? }
# rest of your code
end
Also I would rather post to /movies rather than to /movies/new, that's more REST-wise.
Try if condition to check fields are blank like below -
unless [title, year, gross, poster, trailer].any?(&:blank?)
This will check any of the field should not be nil or blank("").

Accepting Command-Line Arguments into a Ruby Script

I'm trying to use the following code to accept in a file as an argument in Terminal which will then be read and update the body variable with its contents. If the file is not passed in then I want to have the prompt where the user can enter their own body copy.
require 'posterous'
Posterous.config = {
'username' => 'name',
'password' => 'pass',
'api_token' => 'token'
}
include Posterous
#site = Site.primary
#GETS POST TITLE
puts "Post title: "
title = STDIN.gets.chomp()
if defined?(ARGV)
filename = ARGV.first
end
if (defined?(filename))
body = File.open(filename)
body = body.read()
else
puts "Post body: "
body = STDIN.gets.chomp()
end
puts body
When I run the program without passing in a file I get this returned:
Post title:
Hello
posterous.rb:21:in `initialize': can't convert nil into String (TypeError)
from posterous.rb:21:in `open'
from posterous.rb:21:in `'
I'm rather new to ruby and thus am not the best at it. I've tried swapping a lot of things around and changing things but to no avail. What am I doing wrong?
defined?(ARGV) won't return a boolean false, but rather "constant". Since that doesn't evaluate to false, filename gets defined as ARGV[0], which is nil.
>> ARGV
=> []
>> defined?(ARGV)
=> "constant"
?> ARGV.first
=> nil
Instead you might check the length of ARGV:
if ARGV.length > 0
filename = ARGV.first.chomp
end
From the docs:
defined? expression tests whether or not expression refers to anything recognizable (literal object, local variable that has been initialized, method name visible from the current scope, etc.). The return value is nil if the expression cannot be resolved. Otherwise, the return value provides information about the expression.
Michael gave you the basic answer to your question. A slightly more Rubyish way of doing that would be to use ARGF to do the reading; then the conditional is only needed to decide whether or not to print the prompt:
puts "Post title: "
title = gets.chomp
puts "Post body: " if ARGV.length == 0
body = ARGF.gets.chomp
puts body
..of course, if you don't need to anything else with body, you can skip storing the contents of the file(s) and just do
puts ARGF.gets.chomp

Array for errors in sinatra

To manage errors in my address book app i initialize an array like this
err = Array.new
and then when i post something it checks if there are empty fields. If yes, for each empty field it adds a record in the array, and then redirect to /add page, like this
post '/' do
if params[:fname] == ""
err.push "Insert a valid first name"
end
if params[:lname] == ""
err.push "insert a valid last name"
end
if params[:phone] == ""
err.push "insert a valid phone number"
end
if params[:mail] == ""
err.push "insert a valid e-mail address"
end
if err.empty?
c = Contatto.new
c.fname = params[:fname]
c.lname = params[:lname]
c.phone = params[:phone]
c.mail = params[:mail]
c.save
redirect '/'
else
redirect '/add'
end
end
then the add page reads if the array has any record and if yes, cycles it to print each message
get '/add' do
#err = err
#title = 'Aggiungi'
erb :aggiungi
end
<% if #err.any? %>
<div class="error">
<% #err.each do |err| %>
<%= err %><br>
<% end %>
</div>
<% end %>
i think the error is that it re-initialize the array every time it changes from post '/' to get '/add' and so the result is an empty array...
How can i solve? thank you everyone!
If you want data for a specific visitor to persist between requests you need to be storing the error array in either a session or a cookie (session probably makes the most sense).
Luckily sessions in Sinatra are pretty easy: http://www.sinatrarb.com/intro#Using%20Sessions . Once enabled you can put pretty much anything you want into the session hash, so initializing with session[:errors] = [] and pushing with session[:errors] << "An error" should give you the persistence you are looking for.
You're creating a local variable and expecting it to persist between requests. How is this supposed to happen? Sinatra is not psychic, it will only remember what you tell it to remember, and that's usually done through some kind of database or a client-side cookie.
Generally you should render a response page on failure, making use of the errors you've collected, or redirect on success, where the empty errors array is not relevant.
As a matter of style, the more Ruby way to do things like this is:
err = [ ] # Equivalent to Array.new
err << "Example error" # Equivalent to err.push

Resources