Рубиновое троичное состояние, кажется, игнорируется, когда не внутри паренов? - PullRequest
0 голосов
/ 05 октября 2018

Я пытаюсь понять, почему преобразование этой строки if-then-else в троичное выражение (?:) не сработало.Я знаю, что это может быть не самый подходящий код, но я хочу понять, что происходит.

   if a = Artist.find_by(id: params[:artist_id]) then @songs = a.songs else redirect_to(artists_path, alert: "Artist not found") end

Выше if-then-else проходит тесты, и все это хорошо, но когда я пытался сделать этотроичное выражение вроде так :, оно не работает так, как я ожидал.

  a = Artist.find_by(id: params[:artist_id]) ? @songs = a.songs : redirect_to(artists_path, alert: "Artist not found")

, что дает мне следующую ошибку:

1) songs when nested under artists /artists/:artist_id/songs displays the songs with valid artist
     Failure/Error: a = Artist.find_by(id: params[:artist_id]) ? @songs = a.songs : redirect_to(artists_path, alert: "Artist not found")

     NoMethodError:
       undefined method `songs' for nil:NilClass
     # ./app/controllers/songs_controller.rb:4:in `index'
     # /home/dapawn/.rvm/gems/ruby-2.3.3/gems/rack-1.6.4/lib/rack/etag.rb:24:in `call'
     # /home/dapawn/.rvm/gems/ruby-2.3.3/gems/rack-1.6.4/lib/rack/conditionalget.rb:25:in `call'
     # /home/dapawn/.rvm/gems/ruby-2.3.3/gems/rack-1.6.4/lib/rack/head.rb:13:in `call'
     # /home/dapawn/.rvm/gems/ruby-2.3.3/gems/rack-1.6.4/lib/rack/session/abstract/id.rb:225:in `context'
     # /home/dapawn/.rvm/gems/ruby-2.3.3/gems/rack-1.6.4/lib/rack/session/abstract/id.rb:220:in `call'
     # /home/dapawn/.rvm/gems/ruby-2.3.3/gems/railties-4.2.5/lib/rails/rack/logger.rb:38:in `call_app'
     # /home/dapawn/.rvm/gems/ruby-2.3.3/gems/railties-4.2.5/lib/rails/rack/logger.rb:20:in `block in call'
     # /home/dapawn/.rvm/gems/ruby-2.3.3/gems/railties-4.2.5/lib/rails/rack/logger.rb:20:in `call'
     # /home/dapawn/.rvm/gems/ruby-2.3.3/gems/rack-1.6.4/lib/rack/methodoverride.rb:22:in `call'
     # /home/dapawn/.rvm/gems/ruby-2.3.3/gems/rack-1.6.4/lib/rack/runtime.rb:18:in `call'
     # /home/dapawn/.rvm/gems/ruby-2.3.3/gems/rack-1.6.4/lib/rack/lock.rb:17:in `call'
     # /home/dapawn/.rvm/gems/ruby-2.3.3/gems/rack-1.6.4/lib/rack/sendfile.rb:113:in `call'
     # /home/dapawn/.rvm/gems/ruby-2.3.3/gems/railties-4.2.5/lib/rails/engine.rb:518:in `call'
     # /home/dapawn/.rvm/gems/ruby-2.3.3/gems/railties-4.2.5/lib/rails/application.rb:165:in `call'
     # /home/dapawn/.rvm/gems/ruby-2.3.3/gems/rack-1.6.4/lib/rack/urlmap.rb:66:in `block in call'
     # /home/dapawn/.rvm/gems/ruby-2.3.3/gems/rack-1.6.4/lib/rack/urlmap.rb:50:in `each'
     # /home/dapawn/.rvm/gems/ruby-2.3.3/gems/rack-1.6.4/lib/rack/urlmap.rb:50:in `call'
     # /home/dapawn/.rvm/gems/ruby-2.3.3/gems/rack-test-0.6.3/lib/rack/mock_session.rb:30:in `request'
     # /home/dapawn/.rvm/gems/ruby-2.3.3/gems/rack-test-0.6.3/lib/rack/test.rb:244:in `process_request'
     # /home/dapawn/.rvm/gems/ruby-2.3.3/gems/rack-test-0.6.3/lib/rack/test.rb:58:in `get'
     # /home/dapawn/.rvm/gems/ruby-2.3.3/gems/capybara-2.5.0/lib/capybara/rack_test/browser.rb:60:in `process'
     # /home/dapawn/.rvm/gems/ruby-2.3.3/gems/capybara-2.5.0/lib/capybara/rack_test/browser.rb:35:in `process_and_follow_redirects'
     # /home/dapawn/.rvm/gems/ruby-2.3.3/gems/capybara-2.5.0/lib/capybara/rack_test/browser.rb:21:in `visit'
     # /home/dapawn/.rvm/gems/ruby-2.3.3/gems/capybara-2.5.0/lib/capybara/rack_test/driver.rb:42:in `visit'
     # /home/dapawn/.rvm/gems/ruby-2.3.3/gems/capybara-2.5.0/lib/capybara/session.rb:232:in `visit'
     # /home/dapawn/.rvm/gems/ruby-2.3.3/gems/capybara-2.5.0/lib/capybara/dsl.rb:51:in `block (2 levels) in <module:DSL>'
     # ./spec/features/songs_spec.rb:13:in `block (4 levels) in <top (required)>'

Если a равно nil как можноэто будет выполнять истинную часть троичного выражения?

Если я ставлю скобки вокруг условия, как это, это прекрасно работает:

   (a = Artist.find_by(id: params[:artist_id])) ? @songs = a.songs : redirect_to(artists_path, alert: "Artist not found")

Я полагаю, что это должно быть какой-то приоритет,но я просто не вижу этогоЗаранее спасибо, что нашли время ответить и помочь мне учиться.

1 Ответ

0 голосов
/ 05 октября 2018

Это приоритетная вещь.?: имеет более высокий приоритет, чем =, что позволяет назначать в зависимости от условия:

animal = is_dog ? "dog" : "not a dog"

, которое по понятным причинам анализируется как

animal = (is_dog ? "dog" : "not a dog")

Если вы хотите назначить внутриусловие, вам нужны круглые скобки:

(animal = find_animal("dog")) ? "found dog" : "no dog"

В вашем случае

a = Artist.find_by(id: params[:artist_id]) ?
    @songs = a.songs :
    redirect_to(artists_path, alert: "Artist not found")

сначала он оценит Artist.find_by и определит условное условие на основе этого;если он что-то находит, он пытается оценить @songs = a.songs, но a еще не присвоен .a ожидает результата условия и получит либо значение @songs = a.songs, либо значение redirect_to ... после выполнения условия.

Стилистически говоря, я бы предпочел оставить это как if ... then ... else ... end, учитывая, что вы не используете результат ?:.Тернарный условный оператор обычно используется, когда значение, возвращаемое условным выражением, является релевантным, и обе ветви являются относительно простыми выражениями.Я бы использовал if ... then ... else ... end, если возвращаемое значение не используется (как в вашем коде), или если ветви состоят из более чем простого выражения, особенно если многострочный или многострочный оператор:

foo =
  if bar
     do_something
     do_something_else(bar)
     final_result
  else
     do_another_thing
     skip_something_else
     the_other_final_result
  end
...