How to Write a Rails Mixin That Spans Across Model, Controller, and View

How to write a Rails mixin that spans across model, controller, and view

You could pluginize it (use script/generate plugin).

Then in your init.rb just do something like:

ActiveRecord::Base.send(:include, PluginName::Sendable)
ActionController::Base.send(:include, PluginName::SendableController)

And along with your self.included that should work just fine.

Check out some of the acts_* plugins, it's a pretty common pattern (http://github.com/technoweenie/acts_as_paranoid/tree/master/init.rb, check line 30)

Correct way to optimize repeated Rails code

  1. A simple way is to split the code into modules and use mixin.
    A better way is to write your own plugins for your common code.. like act_as_commentable
    you can learn about it here: http://guides.rubyonrails.org/plugins.html

  2. The correct way is to do a comments controller, and have it nested to your models, giving a restful routes like this: /mymodelname/1/comments.
    An easy way to make such controllers is by using inherited_resources plugin.
    scroll down to the "Polymorphic belongs to" section- there is a comments controller example

Access attributes in controller while looping in view

You want to do all the calculation on the server in your controller action before rendering the view.

So in addition to gathering the @deals, you will also set an instance variable for the count.

def index
@deals = Deals.all # or whatever your finder is

@common_listitem_count = ListItem.where(code: @deals.pluck(:code)).count
end

Then just call the count instance variable in the view:

<%= @common_listitem_count %>

Where should I put this code?

Check out the discussion here.

Refactoring ActiveRecord models with a base class versus a base module

There's a fundamental difference between those two methods that all the other answers are missing, and that's rails' implementation of STIs (Single Table Inheritance):

http://api.rubyonrails.org/classes/ActiveRecord/Base.html (Find the "Single Table Inheritance" section)

Basically, if you refactor your Base class like this:

class Base < ActiveRecord::Base
def foo
puts "foo"
end
end

class A < Base
end

class B < Base
end

Then, you are supposed to have a database table called "bases", with a column called "type", which should have a value of "A" or "B". The columns on this table will be the same across all your models, and if you have a column that belongs to only one of the models, your "bases" table will be denormalized.

Whereas, if you refactor your Base class like this:

Module Base
def foo
puts "foo"
end
end

class A < ActiveRecord::Base
include Base
end

class B < ActiveRecord::Base
include Base
end

Then there will be no table "bases". Instead, there will be a table "as" and a table "bs". If they have the same attributes, the columns will have to be duplicated across both tables, but if there are differences, they won't be denomarlized.

So, if one is preferable over the other, yes, but that's specific to your application. As a rule of thumb, if they have the exact same properties or a big overlap, use STI (1st example), else, use Modules (2nd example).

Rails 7 signup form doesn't show error messages

If you look at the logs you can see that Rails is getting an AJAX request in the form of a turbo stream:

Processing by UsersController#create as TURBO_STREAM

Where it should read:

Processing by UsersController#create as HTML

To disable turbo you want need to set a data-turbo="false" attribute on the form:

<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>

<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_with(model: @user, data: { turbo: false }) do |f| %>
<%= render 'shared/error_messages' %>
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control' %>
<%= f.label :email %>
<%= f.email_field :email, class: 'form-control' %>
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>
<%= f.label :password_confirmation, "Confirmation" %>
<%= f.password_field :password_confirmation, class: 'form-control' %>
<%= f.submit "Create my account", class: "btn btn-primary" %>
<% end %>
</div>
</div>

The local: false option only works with the old Rails UJS javascript library which was the default prior to Rails 7. You can also disable Turbo by default with:

import { Turbo } from "@hotwired/turbo-rails"
Turbo.session.drive = false

See:

https://turbo.hotwired.dev/handbook/drive#disabling-turbo-drive-on-specific-links-or-forms

Socket.IO with Ember and Ember-Data

There's a very simple solution to this which I'm using in some of my apps. You can either have a general purpose callback for the socket and accept any kind of data

callback: function(message) {
// this is better than just `eval`
var type = Ember.get(Ember.lookup, message.type);
store.load(type, message.data);
}

or here it is specifically tailored to your use case

socket.on('apartment/new', function(apartment) {
store.load(App.Apartment, apartment);
});

using store.load will load the record data directly into the identity map. There's also loadMany for loading multiple records.



Related Topics



Leave a reply



Submit