Nino Rosella

Joined

2,130 Experience
0 Lessons Completed
2 Questions Solved

Activity

Hi Jacob,

That's been a massive help, so thanks. I just have one small problem now.

When I save the Book and then do

@book.authors

I have two records saved. One is the correct record that was retrieved by the find_or_create_by method. The second record is new and I believe this is being created by the first line of code:

@book = current_user.books.create(book_params)

Is there a way to skip the saving of the new record?
Don't suppose anyone could lend a hand before this drives me insane..? :s

Hi gang...

I have a Book which has_many :authors, through: :book_authors

Instead of creating a new Author each time I create a book I'd like to use find_or_create_by on the author's name attribute. Really struggling to work out where this code should go. Using cocoon gem for the form.

Here's what I currently have that works.

book.rb
class Book < ApplicationRecord

has_many :book_authors
has_many :authors, through: :book_authors
belongs_to :user

accepts_nested_attributes_for :authors, allow_destroy: true
end


author.rb
class Author < ApplicationRecord
has_many :book_authors
has_many :books, through: :book_authors
end

book_author.rb
class BookAuthor < ApplicationRecord
belongs_to :book
belongs_to :author
end

books_controller.rb
class BooksController < ApplicationController
before_action :authenticate_user!

def new
@book = Book.new
@book.authors.new
end

def create
@book = current_user.books.create(book_params)
@book.authors.each {|author| author.user_id = current_user.id}

if @book.save
    redirect_to book_path(@book)
else
    render :new
end

end

private
def book_params
params.require(:book).permit(:title, authors_attributes: [:id, :name, :_destroy])
end
end


new.html.erb
<%= simple_form_for @book do |f| %>
<%= f.input :title %>
<div id='authors'>
<%= f.simple_fields_for :authors do |author| %>
<%= render 'author_fields', :f => author %>
<% end %>
<div class='links'>
<br>
<%= link_to_add_association 'Add another author', f, :authors %>
</div>
</div>
<% end %>

_author_fields.html.erb
<div class="nested-fields">
<%= f.input :name, label: "Author(s)", collection: @authors, value_method: :name, input_html: {value: @authors, class: 'new-author'} %>
<%= link_to_remove_association "Remove this author", f %>
</div>

In my Rails 5.1 app I am trying to create a tagging system from scratch. I have been using the Comments with Polymorphic Associations episode as a template.

I want Tags to be a polymorphic has_many :through association so that I can tag multiple models.

Currently I'm able to create a Tag (and the associated Tagging) in the console by doing: Note.last.tags.create(name: "example") which generates the correct SQL:

Note Load (0.2ms)  SELECT  "notes".* FROM "notes" ORDER BY "notes"."id" DESC LIMIT $1  [["LIMIT", 1]]
(0.2ms)  BEGIN
SQL (0.4ms)  INSERT INTO "tags" ("name", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id"  [["name", "example"], ["created_at", "2017-10-21 14:41:43.961516"], ["updated_at", "2017-10-21 14:41:43.961516"]]
Note Load (0.3ms)  SELECT  "notes".* FROM "notes" WHERE "notes"."id" = $1 LIMIT $2  [["id", 4], ["LIMIT", 1]]
SQL (0.4ms)  INSERT INTO "taggings" ("created_at", "updated_at", "tag_id", "taggable_id", "taggable_type") VALUES ($1, $2, $3, $4, $5) RETURNING "id"  [["created_at", "2017-10-21 14:41:43.978286"], ["updated_at", "2017-10-21 14:41:43.978286"], ["tag_id", 9], ["taggable_id", 4], ["taggable_type", "Note"]]

But when trying to create a Tag and its associations through my form it doesn't work. I can create the Tag but no Tagging.

controllers/notes/tags_controller.rb

class Notes::TagsController < TagsController
  before_action :set_taggable

  private

  def set_taggable
    @taggable = Note.find(params[:note_id])
  end
end

controllers/tags_controller.rb

class TagsController < ApplicationController
  before_action :authenticate_user!

  def create
    @tag = @taggable.tags.new(tag_params)
    @tag.user_id = current_user.id

    if @tag.save
      redirect_to @taggable, success: "New tag created."
    else
      render :new
    end
  end

  private

  def tag_params
    params.require(:tag).permit(:name)
  end

end

routes.rb

...
resources :notes, except: [:index] do
  resources :tags, module: :notes
end
...

.

class Note < ApplicationRecord
  belongs_to :notable, polymorphic: true
  has_many :taggings, as: :taggable
  has_many :tags, through: :taggings
end

class Tag < ApplicationRecord
  has_many :taggings
  has_many :taggables, through: :taggings
end

class Tagging < ApplicationRecord
  belongs_to :tag
  belongs_to :taggable, polymorphic: true
end

notes/show.html.erb

<p><%= @note.body %></p>
<%= render partial: 'tags/tags', locals: { taggable: @note } %>
<%= render partial: 'tags/form', locals: { taggable: @note }  %>

tags/form.html.erb

<%= simple_form_for [taggable, Tag.new] do |f| %>
  <%= f.input :name %>
  <%= f.submit %>
<% end %>

Posted in Cross-platform rich text editing

Thanks, Chris.

Will try with markdown first and take it from there!

Posted in Cross-platform rich text editing

I'm building a note-taking Rails 5 app that will be a web app and will also act as a backend for OSX and Windows apps in the future. One of the key features is the rich editing of text - bold, italics, size, colour, highlights etc very much like the feature set of Evernote.

What options should I be considering in regards to which text format to use and save in the db? HTML seems too messy (especially when using it with the native desktop apps), markdown doesn't seem to include enough features...

Getting quite lost and confused. As always, your help is appreciated Go Rails fam.

Posted in Prevent spam bots from hitting app

Jacob, I did initially try blacklisting the range but there were so many different ips that I simply couldn't keep up. They were coming in like this:

122.6.249.70
123.170.194.141
106.113.26.18
107.118.193.247.103

It got a bit much.

However, I seem to have fixed it. I added the following two lines to the bottom of my rack-attack.rb file:

  blocklist('block bad UA logins') do |req|
    req.path == '/jobs/389-commercial-vehicle-technician-northside-truck-van-york-mercedes-benz-uk-ltd/email_to_friend' && req.post? && req.user_agent == 'BadUA'
  end
blocklisted_response = lambda do |env|
  # Using 503 because it may make attacker think that they have successfully
  # DOSed the site. Rack::Attack returns 403 for blocklists by default
    [ 503, {}, ['Blocked']]
  end

Posted in Prevent spam bots from hitting app

Hi guys and gals

Wasn't sure which category to put this in but here goes anyway...

I have a Rails 5 app in production hosted on Heroku. I recently noticed a particularly high load on the servers and on further investigation it looks as though it's all from a group of spam bots.

These bots were hitting an 'email to friend' form that I had on the show page and available to logged-out users. I've since made the form available only to logged-in and authenticated users. I also deleted the specific record that the bots were targeting in the db, yet this hasn't done anything to stop the bots from hitting the route. (They only seem to be targeting a specific record...)

I then installed the rack-attack gem to try and throttle requests to this specific path (as well as the sign_up path for good measure), but the problem I have is that these spam requests originate from a different ip address every single time and the rack-attack gem only throttles requests from a single ip.

Can anyone provide any assistance on how to prevent these bots from hitting my site?

Here is the print out from the Heroku logs of a single request:

2016-11-26T08:01:22.784341+00:00 heroku[router]: at=info method=POST path="/jobs/389-commercial-vehicle-technician-northside-truck-van-york-mercedes-benz-uk-ltd/email_to_friend" host=www.example.com request_id=02689424-de9c-4a25-96c8-8f510a587836 fwd="203.160.52.159" dyno=web.1 connect=1ms service=11ms status=404 bytes=1812
2016-11-26T08:01:22.757585+00:00 app[web.1]: [02689424-de9c-4a25-96c8-8f510a587836] Started POST "/jobs/389-commercial-vehicle-technician-northside-truck-van-york-mercedes-benz-uk-ltd/email_to_friend" for 203.160.52.159 at 2016-11-26 08:01:22 +0000
2016-11-26T08:01:22.759320+00:00 app[web.1]: [02689424-de9c-4a25-96c8-8f510a587836]   
2016-11-26T08:01:22.759371+00:00 app[web.1]: [02689424-de9c-4a25-96c8-8f510a587836] ActionController::RoutingError (No route matches [POST] "/jobs/389-commercial-vehicle-technician-northside-truck-van-york-mercedes-benz-uk-ltd/email_to_friend"):
2016-11-26T08:01:22.759421+00:00 app[web.1]: [02689424-de9c-4a25-96c8-8f510a587836]   
2016-11-26T08:01:22.759493+00:00 app[web.1]: [02689424-de9c-4a25-96c8-8f510a587836] vendor/bundle/ruby/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/debug_exceptions.rb:53:in `call'
2016-11-26T08:01:22.759535+00:00 app[web.1]: [02689424-de9c-4a25-96c8-8f510a587836] vendor/bundle/ruby/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/show_exceptions.rb:31:in `call'
2016-11-26T08:01:22.759575+00:00 app[web.1]: [02689424-de9c-4a25-96c8-8f510a587836] vendor/bundle/ruby/2.3.0/gems/railties-5.0.0.1/lib/rails/rack/logger.rb:36:in `call_app'
2016-11-26T08:01:22.759639+00:00 app[web.1]: [02689424-de9c-4a25-96c8-8f510a587836] vendor/bundle/ruby/2.3.0/gems/railties-5.0.0.1/lib/rails/rack/logger.rb:24:in `block in call'
2016-11-26T08:01:22.759726+00:00 app[web.1]: [02689424-de9c-4a25-96c8-8f510a587836] vendor/bundle/ruby/2.3.0/gems/activesupport-5.0.0.1/lib/active_support/tagged_logging.rb:26:in `tagged'
2016-11-26T08:01:22.759685+00:00 app[web.1]: [02689424-de9c-4a25-96c8-8f510a587836] vendor/bundle/ruby/2.3.0/gems/activesupport-5.0.0.1/lib/active_support/tagged_logging.rb:70:in `block in tagged'
2016-11-26T08:01:22.759766+00:00 app[web.1]: [02689424-de9c-4a25-96c8-8f510a587836] vendor/bundle/ruby/2.3.0/gems/activesupport-5.0.0.1/lib/active_support/tagged_logging.rb:70:in `tagged'
2016-11-26T08:01:22.759905+00:00 app[web.1]: [02689424-de9c-4a25-96c8-8f510a587836] vendor/bundle/ruby/2.3.0/gems/railties-5.0.0.1/lib/rails/rack/logger.rb:24:in `call'
2016-11-26T08:01:22.759944+00:00 app[web.1]: [02689424-de9c-4a25-96c8-8f510a587836] vendor/bundle/ruby/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/request_id.rb:24:in `call'
2016-11-26T08:01:22.760009+00:00 app[web.1]: [02689424-de9c-4a25-96c8-8f510a587836] vendor/bundle/ruby/2.3.0/gems/rack-2.0.1/lib/rack/method_override.rb:22:in `call'
2016-11-26T08:01:22.760265+00:00 app[web.1]: [02689424-de9c-4a25-96c8-8f510a587836] vendor/bundle/ruby/2.3.0/gems/rack-2.0.1/lib/rack/runtime.rb:22:in `call'
2016-11-26T08:01:22.760333+00:00 app[web.1]: [02689424-de9c-4a25-96c8-8f510a587836] vendor/bundle/ruby/2.3.0/gems/activesupport-5.0.0.1/lib/active_support/cache/strategy/local_cache_middleware.rb:28:in `call'
2016-11-26T08:01:22.760365+00:00 app[web.1]: [02689424-de9c-4a25-96c8-8f510a587836] vendor/bundle/ruby/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/executor.rb:12:in `call'
2016-11-26T08:01:22.760394+00:00 app[web.1]: [02689424-de9c-4a25-96c8-8f510a587836] vendor/bundle/ruby/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/static.rb:136:in `call'
2016-11-26T08:01:22.760422+00:00 app[web.1]: [02689424-de9c-4a25-96c8-8f510a587836] vendor/bundle/ruby/2.3.0/bundler/gems/heroku-deflater-60d92ba0f8ae/lib/heroku-deflater/skip_binary.rb:19:in `call'
2016-11-26T08:01:22.760478+00:00 app[web.1]: [02689424-de9c-4a25-96c8-8f510a587836] vendor/bundle/ruby/2.3.0/gems/rack-2.0.1/lib/rack/deflater.rb:35:in `call'
2016-11-26T08:01:22.760522+00:00 app[web.1]: [02689424-de9c-4a25-96c8-8f510a587836] vendor/bundle/ruby/2.3.0/bundler/gems/heroku-deflater-60d92ba0f8ae/lib/heroku-deflater/serve_zipped_assets.rb:50:in `call'
2016-11-26T08:01:22.760552+00:00 app[web.1]: [02689424-de9c-4a25-96c8-8f510a587836] vendor/bundle/ruby/2.3.0/gems/rack-2.0.1/lib/rack/sendfile.rb:111:in `call'
2016-11-26T08:01:22.760581+00:00 app[web.1]: [02689424-de9c-4a25-96c8-8f510a587836] vendor/bundle/ruby/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/ssl.rb:83:in `call'
2016-11-26T08:01:22.760610+00:00 app[web.1]: [02689424-de9c-4a25-96c8-8f510a587836] vendor/bundle/ruby/2.3.0/gems/railties-5.0.0.1/lib/rails/engine.rb:522:in `call'
2016-11-26T08:01:22.760650+00:00 app[web.1]: [02689424-de9c-4a25-96c8-8f510a587836] vendor/bundle/ruby/2.3.0/gems/puma-3.6.0/lib/puma/configuration.rb:225:in `call'
2016-11-26T08:01:22.760699+00:00 app[web.1]: [02689424-de9c-4a25-96c8-8f510a587836] vendor/bundle/ruby/2.3.0/gems/puma-3.6.0/lib/puma/server.rb:578:in `handle_request'
2016-11-26T08:01:22.760741+00:00 app[web.1]: [02689424-de9c-4a25-96c8-8f510a587836] vendor/bundle/ruby/2.3.0/gems/puma-3.6.0/lib/puma/server.rb:415:in `process_client'
2016-11-26T08:01:22.760782+00:00 app[web.1]: [02689424-de9c-4a25-96c8-8f510a587836] vendor/bundle/ruby/2.3.0/gems/puma-3.6.0/lib/puma/server.rb:275:in `block in run'
2016-11-26T08:01:22.760849+00:00 app[web.1]: [02689424-de9c-4a25-96c8-8f510a587836] vendor/bundle/ruby/2.3.0/gems/puma-3.6.0/lib/puma/thread_pool.rb:116:in `block in spawn_thread'

As I mentioned above, all these spam requests are hitting the following path:

path="/jobs/389-commercial-vehicle-technician-northside-truck-van-york-mercedes-benz-uk-ltd/email_to_friend"

Currently getting a request once every couple of seconds or so...

Posted in Remove omniauth and convert existing users

I can't believe I didn't think of that...

Yeah, it was a validation failing on a username column that I have.

Thanks Chris

Posted in Remove omniauth and convert existing users

Hi Chris,

Sorry the question wasn't too clear - I rushed it! What I was trying to say is that in the user table I have a column named provider which stores the value "linkedin" for the LinkedIn signups. On a single record I was trying to modify the value in the rails console, but when I tried to save the record it was returning false.

Hmm I think this whole process is going to be fairly messy. This is the first and last time I ever use third-part sign up!

Posted in Remove omniauth and convert existing users

Hi everyone

I have LinkedIn omniauth sign in up and working on my Rails 5 app in accordance with the Devise guide: https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview

I have some active users that have signed up using LinkedIn but now I would like to remove this functionality from the site. I thought that if I simply changed the provider of a user from "linkedin" back to nil (in the console) then that user could sign in to my app using the email address they have associated to LinkedIn. When I try to change the provider on a test account the change fails.

Anyone have any ideas?

Thanks