AlchemyCMS / alchemy_cms

Alchemy is the Open Source Rails CMS framework for the component based web that can be used as classic server side rendered or headless CMS.
https://www.alchemy-cms.com
BSD 3-Clause "New" or "Revised" License
846 stars 314 forks source link

No icons in admin interface (CORS problem) #2937

Closed afdev82 closed 1 month ago

afdev82 commented 5 months ago

Hello,

I have updated my application to Rails 7.1 and Alchemy 7.2.2 and the icons on the admin interface are not showing up anymore. I am quite sure it worked before with Rails 7.0 and Alchemy 7.0.0. I have investigated and found that the svg file remixicon.symbol.svg doesn't get loaded from the asset host I'm using with the "not same-origin" error in the network panel of the developer tools. The request doesn't contain the "Origin" header, while all the other assets have it. I don't know if it's an issue with AlchemyCMS or Rails. Could someone help me on that? Thank you for your support.

tvdeyen commented 5 months ago

Could you show some output of the network panel where it tries to load the icon sprite? And examine the svg tag of the item that is in the DOM? Especially the href attribute.

Alchemy CMS - Dashboard 2024-06-27 21-15-58

afdev82 commented 5 months ago

Yes,

this is the svg in the DOM:

Screenshot 2024-06-28 at 09 04 14

And this is the request of the icon sprite:

Screenshot 2024-06-28 at 09 05 37

As you can see there is no ORIGIN header, but I don't have it for other assets too (css & js):

Screenshot 2024-06-28 at 09 07 15

I have some Sec-Fetch-* header, I would have expected something like that:

Sec-Fetch-Dest: image Sec-Fetch-Mode: no-cors Sec-Fetch-Site: cross-site

But I was not able to find where these headers are set.

tvdeyen commented 5 months ago

There is nothing we can do on our end I fear. The file is served from your cdn. You probably need to add svg format as asset type to your cdn configuration?

afdev82 commented 5 months ago

Hi,

yes, it's what I thought too. But I haven't changed my server configuration and the problem was there right after the update of Rails & AlchemyCMS, so I think something in the update has been changed. Maybe (most probably) it's the Rails update, but I have asked here before to get some hints. I will continue my research and let you know, thanks.

tvdeyen commented 2 months ago

@afdev82 is this still a problem? I just successfully downloaded the svg icon sprite from your CDN.

https://ad-notam.static-assets.net/www/assets/remixicon.symbol-d60b3b3ad3291e7f9b290de7ba76b4d75b1034fad1c21567192fa7ef4fa1a9c9.svg

Can you confirm it works now?

afdev82 commented 2 months ago

Hi Thomas,

no, unfortunately it doesn't work... From the website I am still getting the error. If I open that URL directly to download the file it works. The CDN is on the same server, the assets are served directly with nginx from the public directory of the rails project, I haven't changed anything there.

I have found this web page that probably explains why I don't have the CORS header in the request for the SVG, but still I don't get how to solve the problem:

Unfortunately, there currently isn’t a way to indicate that normal CSS image requests, such as background-image references, should request cross-origin permissions. You can use an HTML “preload” element to force the browser to fetch the image file, and request cross-origin permissions when it does.

tvdeyen commented 2 months ago

@afdev82 thanks for the insights. I hopefully fixed it in https://github.com/AlchemyCMS/alchemy_cms/pull/3046

Do you mind testing it?

afdev82 commented 2 months ago

Thank you Thomas,

I switched from the master branch to the 7.3-stable branch to be able to test your changes (I had to apply the migrations for the v7.3 before), but I am getting the following error from Sprockets:

cannot load such file -- sassc

I don't know why, because I haven't changed the Sprocket version (4.2.1) or my configuration (apart from adding the custom.css alchemy admin css), I have just changed the Alchemy version:

$ bundle info alchemy_cms
  * alchemy_cms (7.3.0.a 4455010)
$ bundle info alchemy_cms
  * alchemy_cms (7.3.0 115da13)

I am still trying to get around this problem, because I am getting it also with the preload-svg-icon-font branch.

I think it has something to do with the new custom.css entrypoint, because if I am using sprocket to compile the css I have this error. But I am not using sprockets to compile the sass files anymore, I am using dartsass-rails gem. I don't have any css entry in the config/manifest.js file, but the precompiled files are in the assets/builds folder. I have tried adding an empty custom.css file in the assets/stylesheets/alchemy/adminfolder and it worked, but I have some styles to be applied, so I need to compile that file.

afdev82 commented 2 months ago

Maybe I have found the problem, my custom file is directly in builds, not in builds/alchemy/admin ...

tvdeyen commented 2 months ago

Yes, it seems it still tries to precompile the .scss files from Alchemy. We now pre-compile them into the gem. The upgrader should have removed all custom .scss from the host app. Can you verify that you do not import and Alchemy Sass files. Look for @import "alchemy/..." in your project.

afdev82 commented 2 months ago

No Thomas, the problem was because I didn't have the custom.css under assets/builds/alchemy/admin, but in assets/builds, so than sprockets was precompiling the asset, because I had the entry in the config/manifest.js pointing to the file. Now I have moved the file in the right position, using dartsass-rails and it works. I will test now in production, where I can verify the CORS issue and let you know.

afdev82 commented 2 months ago

I have an unrelated problem to solve before I could publish it to test. In one of my resource section in the admin interface I am getting the following error:

ActionView::Template::Error undefined method `admin_user_path' for an instance of ActionDispatch::Routing::RoutesProxy

I have seen I need to change the partial from tableto resource_table in the index view for the resource and in fact for another resource is working now, but for the other not. I don't know where the path gets called, If I comment the line

<%= render Alchemy::Admin::Resource::Table.new(resources_instance_variable, query: @query, search_filter_params: search_filter_params, icon: local_assigns[:icon]) %>

In the resource_table partial the error is gone. But that line is the same as before in the table partial, I don't understand what has changed.

tvdeyen commented 2 months ago

Probably the controller scope. Is this your own users controller? Please try adding main_app as prefix to the route helper to access the host apps route

afdev82 commented 2 months ago

I have these 2 resources in my routes:

namespace :admin do
  resources :users, only: :index
  namespace :configurations do
    resources :configurations, only: :index
  end
end

And I have my own Admin::UsersController in app/controllers/admin/users_controller.rb

module Admin
  class UsersController < Alchemy::Admin::ResourcesController

Please try adding main_app as prefix to the route helper to access the host apps route

Hm... where exactly do you mean to add the prefix? I am not using the route helper directly, in fact I don't know where it gets called. I rely on the index action of Alchemy::Admin::ResourcesController.

tvdeyen commented 2 months ago

Thanks. That makes sense. Can you show me how you have configured the users module in your alchemy.rb initializer?

afdev82 commented 2 months ago

Yes,

this is my initializer:

Rails.application.config.to_prepare do
  Alchemy::Modules.register_module(
    name: 'presets',
    order: 1,
    navigation: {
      name: 'modules.presets',
      controller: '/admin/configurations/configurations',
      action: 'index'
    }
  )

  Alchemy::Modules.register_module(
    name: 'users',
    order: 2,
    navigation: {
      icon: 'user',
      name: 'modules.users',
      controller: '/admin/users',
      action: 'index'
    }
  )
end

Alchemy.user_class_primary_key = :user_id
afdev82 commented 2 months ago

@tvdeyen I have found the problem. In my routes I had only the index path defined:

resources :users, only: :index

but the resources table needs also the new and edit paths for the resource. In fact, I didn't use them, that's why I didn't have the paths. Now I have only to migrate the previous buttons I had in each row to the new structure. Is there some document on those changes or do I need to read the code?

tvdeyen commented 2 months ago

@afdev82

I have found the problem.

glad you found it.

Now I have only to migrate the previous buttons I had in each row to the new structure.

Just for the record, you do not have to migrate the partial (yet). Using the old _table partial still works. It is deprecated, though, and will be removed someday.

Is there some document on those changes or do I need to read the code?

No documentation yet, sorry. You can use this file as example.

https://github.com/AlchemyCMS/alchemy-devise/blob/main/app/views/alchemy/admin/users/_resource_table.html.erb

afdev82 commented 2 months ago

and will be removed someday.

It has been removed from master already... And also the method used to render the row for the resource. So I assume I have to use the new component syntax to add the buttons I need. I will try to do that and finally I could be able to test in production.

afdev82 commented 2 months ago

It was not so difficult to migrate to the new structure. Anyway I have tested the branch and it still doesn't work. Same error. I have tried to install also the rack-cors gem, but it doesn't work either 😬

But I wonder why I have this issue and you or others don't... What's the difference in the setup? If you use a CDN and get the images from there, you should have the same issue 🤔

tvdeyen commented 2 months ago

But I wonder why I have this issue and you or others don't... What's the difference in the setup? If you use a CDN and get the images from there, you should have the same issue 🤔

We do not serve assets from a dedicated CDN subdomain. We just use the Rails app (and a HTTP Proxy cache) to serve the assets.

afdev82 commented 2 months ago

But I wonder why I have this issue and you or others don't... What's the difference in the setup? If you use a CDN and get the images from there, you should have the same issue 🤔

We do not serve assets from a dedicated CDN subdomain. We just use the Rails app (and a HTTP Proxy cache) to serve the assets.

OK, I thought it was a pretty common configuration to use a dedicated asset host. I could disable it anyway, if I can't solve this problem.

tvdeyen commented 2 months ago

Yeah. A very outdated thing to do. With HTTP2 and modern browsers you do not need to load assets from another host. This was when browsers weren't able to load more than 4 things from the same hostname.

afdev82 commented 2 months ago

Yeah. A very outdated thing to do. With HTTP2 and modern browsers you do not need to load assets from another host. This was when browsers weren't able to load more than 4 things from the same hostname.

Yes, I have read already something like that. I then would save me other headaches on this matter just removing the asset host.

afdev82 commented 1 month ago

I have done in this way and obviously the problem is solved.