React Error (Only a ReactOwner can have refs.) - ruby-on-rails

I've just installed a fresh react into my rails project with 'React-rails' and added searchkit on top of it. But I'm getting some errors with it.
Uncaught Invariant Violation: addComponentAsRefTo(...): Only a ReactOwner can have refs. You might be adding a ref to a component that was not created inside a component's render method, or you have multiple copies of React loaded.
app/assets/javascripts/components/search.js.jsx
const host = "http://demo.searchkit.co/api/movies"
const sk = new Searchkit.SearchkitManager(host, {})
var Search = React.createClass({
render: function() {
const SearchkitProvider = Searchkit.SearchkitProvider;
const Searchbox = Searchkit.SearchBox;
const Hits = Searchkit.Hits;
const NoHits = Searchkit.NoHits;
const HitsStats = Searchkit.HitsStats;
const Layout = Searchkit.Layout;
const LayoutBody = Searchkit.LayoutBody;
const LayoutResults = Searchkit.LayoutResults;
const SearchBox = Searchkit.SearchBox;
const TopBar = Searchkit.TopBar;
const SideBar = Searchkit.SideBar;
const ActionBar = Searchkit.ActionBar;
const ActionBarRow = Searchkit.ActionBarRow;
const HierarchicalMenuFilter = Searchkit.HierarchicalMenuFilter;
const RefinementListFilter = Searchkit.RefinementListFilter;
const SelectedFilters = Searchkit.SelectedFilters;
const ResetFilters = Searchkit.ResetFilters;
const MovieHitsGridItem = Searchkit.MovieHitsGridItem;
return (<div>
<SearchkitProvider searchkit={sk}>
<Layout>
<TopBar>
<SearchBox autofocus={true} searchOnChange={true} prefixQueryFields={["actors^1","type^2","languages","title^10"]}/>
</TopBar>
<LayoutBody>
<SideBar>
<HierarchicalMenuFilter fields={["type.raw", "genres.raw"]} title="Categories" id="categories"/>
<RefinementListFilter id="actors" title="Actors" field="actors.raw" operator="AND" size={10}/>
</SideBar>
<LayoutResults>
<ActionBar>
<ActionBarRow>
<HitsStats/>
</ActionBarRow>
<ActionBarRow>
<SelectedFilters/>
<ResetFilters/>
</ActionBarRow>
</ActionBar>
<Hits mod="sk-hits-grid" hitsPerPage={10} itemComponent={MovieHitsGridItem} sourceFilter={["title", "poster", "imdbId"]}/>
<NoHits/>
</LayoutResults>
</LayoutBody>
</Layout>
</SearchkitProvider>
</div>);
}
});
Fairly new with React, so not too sure why these problems are occuring?
Thanks

Ok, I just browsed through this searchkit library. Based on the fact it's a React component and you are using react-rails, I'm almost certain you are running into the issue of having two React instances at one time. react-rails drawback is the difficulty to integrate external libraries with it. It's quick to setup and start using but as soon as you want to install other react libraries, you will hit a wall.
I had this issue before and what I did was to use https://github.com/netguru/react_webpack_rails instead. If you want something abit more then have a look at https://github.com/shakacode/react_on_rails. These two options require more effort to setup but well worth it if you are serious about React and its ecosystem.
BTW: Searchkit looks great!

It seems I'm about late for the party but, just in case, someone may experience this issue again and need a more direct solution.
For your reference:
Rails 5.2.0
Ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-darwin17]
React-rails (2.3.1)
I believe this could happen on different rails and ruby versions too.
As like what #kasperite said, I'm sure you are having two React instances by mistake. You are either 'require react' twice or running into the dual instances by the 'require_tree .' in the 'application.js' file.
To be more specific, you should check the following lines in the 'application.js' file:
//= require react
//= require react_ujs
//= require components
//= require_tree .
The issue is that you first load React by require react directive, then load it again using the require_tree . directive.
Ref: https://guides.rubyonrails.org/asset_pipeline.html#manifest-files-and-directives
Or direct quote from the official guide as in the above link
The require_tree directive tells Sprockets to recursively include all JavaScript files in the specified directory into the output. These paths must be specified relative to the manifest file. You can also use the require_directory directive which includes all JavaScript files only in the directory specified, without recursion.
To sort the issue, you just need to completely delete the require_tree . directive or unset it by removing the equal sign - turn this //= require_tree . to // require_tree .
Hope this help and cheers.

Related

Graphql Ruby - Cannot read property 'types' of undefined at buildClientSchema - rails 6 API only

I get this error on load when I try to load the graphiql client with Rails 6, specifically wanting to use the Documentation Explorer.
TypeError: Cannot read property 'types' of undefined
at buildClientSchema (http://localhost:3000/assets/graphiql/rails/application-6f03c7a92432765b0fbe671bfb7a292ee6c37e6704b6e6ac95587e45676bbf72.js:34102:72)
at http://localhost:3000/assets/graphiql/rails/application-6f03c7a92432765b0fbe671bfb7a292ee6c37e6704b6e6ac95587e45676bbf72.js:2795:55
I tried deleting my graphql directory and re-doing the rails generate graphql:install.
I am using
rails 6
graphiql-rails (1.7.0)
graphql (1.10.5)
I originally built it as API only (and removed unnecessary files, including the assets) but then added the necessary configurations to run graphiql in local development, including adding an app/assetts/config/manifest.js with
//= link_tree ../images
//= link_directory ../javascripts .js
//= link_directory ../stylesheets .css
I was able to look into it more - I made a breakpoint in the chrome debugger for line 34,102, which has the following code:
function buildClientSchema(introspection, options) {
// Get the schema from the introspection result.
var schemaIntrospection = introspection.__schema;
// Converts the list of types into a keyMap based on the type names.
var typeIntrospectionMap = (0, _keyMap2.default)(schemaIntrospection.types, function (type) {
return type.name;
});
..... more code ......
The issue is with schemaIntrospection.types, schemaIntrospection is undefined. So above, I inspected the introspection variable which calls introspection.__schema - The introspection variable looked like:
{"Schema":
{"queryType": {"name":"Query"},
"mutationType": {"name":"Mutation"},
"subscriptionType":null,
.... more JSON ...
So, what I ended up doing is instead of having var schemaIntrospection = introspection.__schema;, I set the schemaIntrospection variable using the correct key:
var schemaIntrospection = introspection.Schema;
And it worked! For that specific call only :/ , as I had used the interactive debugger
Does anyone know how I can fix this with ruby-graphql/graphiql more permanently?
I want to be able to use the Documentation Explorer
Thanks!
Circling back, I was migrating from a REST based API to Graphql. My old project had a middleware (https://github.com/vigetlabs/olive_branch) which I had forgotten to disable, so this was causing it to auto change snake case (which it identified __schema as snake case) to CamelCase. My bad about this, but wanted to follow up in case anyone else had issues, maybe check your middlewares.

How to migrate requiring of select2.js from sprockets to webpacker

I'm in the process of migrating a Rails 5.1.5 project, which uses CoffeeScript, from using sprockets to using webpacker. The project also uses select2.js. With sprockets, I did the following:
Install jquery-rails (jQuery is a dependency for select2).
Put select2.js code in vendor/assets/javscripts.
In application.js.coffee, add:
#= require select2
After that I was able to use select2 to in my application.js.coffee file:
$(document).on 'turbolinks:load' ->
$('select').select2
So far I've described the pretty standard way of including/using javascript libraries with sprockets.
However, with webpacker I can't make select2 work and I'm not sure why. I have two hypothesis:
I'm not importing/requiring it properly;
it doesn't find jQuery at some point of the load process;
So for jQuery, I did the following:
yarn add jquery
included in my environment.js:
const webpack = require('webpack');
environment.plugins.append('Provide', new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
}));
I've removed the jquery-rails gem, as well as #= require 'jquery' and tested that jquery works, so I guess I have correctly included it. However, I tried several ways of importing select2 (using es6 imports) and none of them worked. I tried:
import select2 from 'select2';
import select2 from 'select2/dist/js/select2'
import select2 from 'select2/dist/js/select2.js'
import 'select2/dist/js/select2.js'
I even tried to import it from the old vendor location by writing inside app/javascript/pack/application.js.coffee:
import '../../../vendor/assets/javascripts/select2'
I can confirm that the file contents is imported, as I put a console.log within the select2 file under node_modules/select2/dist/js/select.js and it did get printed. However, I also get the error TypeError: $(...).select2 is not a function when I execute $('select').select2() in the browser's dev tool console.
What am I missing or doing wrong?
P.S. I can provide much more info, but I didn't want my question to get any more bloated.
P.P.S. With my modest JS knowledge, I looked at the source code but couldn't recognize what exactly they are exporting and how am I supposed to import it.
I know this is an old post, but just in case someone else could benefit:
app/javascript/packs/application.js
...other requires...
require('select2')
window.Rails = Rails
import 'bootstrap'
...other imports...
import 'select2'
import 'select2/dist/css/select2.css'
$(document).on("turbolinks:load", () => {
$('.select2').select2()
})
My similar problem
I have stumble upon the same problem with another web component (Switchery):
I imported the component with yarn add switchery (no error)
I could import it correctly through WebPack with import 'switchery' (no error bundling the pack)
But when I was trying to use the Switchery object in the browser like they say in the doc:
var elem = document.querySelector('.js-switch');
var init = new Switchery(elem);
I would get the error: ReferenceError: Switchery is not defined
Note: I didn't want to install RequireJS as WebPack is supposed to do the same thing (and even better) nowadays.
My solution:
The problem was the webpack doesn't expose the pack-generated variables and classes in the global scope!
So to fix this, I needed to do two things:
Explicitly give a name to the imported class from Switchery:
import Switchery from 'switchery'
Use this Class only in the same JS file where the import was done
Testing hack:
If you want to try that out and "go back" to the mess that sprocket allowed, in the same file, you can expose "globally" the variable so you can use in from the browser:
import Switchery from 'switchery'
window.Switchery = Swicthery
now you can execute the switchery almost like in the example:
var init = new window.Switchery(elem);
Hope that helps...

Using 'material-ui' with react-rails gem?

I would like to use the material-ui component library in my Rails 4 app. I am currently using the react-rails gem to add .jsx compilation to the asset pipeline. I have added material-ui via rails-assets in the gemfile like so:
source 'https://rails-assets.org' do
gem 'rails-assets-material-ui'
end
And I have required the library in my application.js file like so:
//= require material-ui
However I keep getting the error "couldn't find file 'material-ui". How can I use the material-ui component library in my Rails app with the react-rails gem?
Ok so here is what I have working so far...
to the gemfile I have added:
gem 'react-rails'
gem "browserify-rails"
This gives us our react library, helpers and jsx compilation as well as the ability to use the require() sytax to require modules in our JS. browserify-rails also allows us to require npm modules in your Rails assets via a package.json file.
We can add the material-ui library to our app via this package.json file...
"dependencies" : {
"browserify": "~> 10.2.4",
"browserify-incremental": "^3.0.1",
"material-ui": "0.13.1"
},
The material ui library uses the require syntax to join all the different jsx component files together in the right order so this is why we need to use browserify-rails.
Next to keep our react code together I made a new directory in asset/javascripts called /react...
react
L /components
L react.js
L react-libraries.js
L theme.js
Now as part of 'material-ui' dependencies we have the react library. This means at the moment we have two copies of the library. One from the 'react-rails' gem and one from the 'material-ui' library dependencies from 'browserify-rails'. Lets use the one from 'material-ui' dependencies and leave the one from 'react-rails'.
in react.js:
//= require ./react-libraries
//= require react_ujs
//= require_tree ./components
Then in react-libraries.js
//React Library
React = require('react');
//Material Design Library
MaterialUi = require('material-ui/lib');
injectTapEventPlugin = require('react-tap-event-plugin'); injectTapEventPlugin();
//Material Design Library Custom Theme
MyRawTheme = require('./theme');
ThemeManager = require('material-ui/lib/styles/theme-manager');
Then we want to include all of this in the asset pipeline with...
//= require react/react
in application.js.
Now you can write your components in jsx files in /react/components/
You may also want to namespace your components with...
//Custom Components Namespace
Components = {};
in react-libraries.js
You can customise your theme in theme.js like this...
Colors = require('material-ui/lib/styles/colors');
ColorManipulator = require('material-ui/lib/utils/color-manipulator');
Spacing = require('material-ui/lib/styles/spacing');
module.exports = {
spacing: Spacing,
fontFamily: 'Roboto, sans-serif',
palette: {
primary1Color: Colors.grey300,
primary2Color: Colors.grey300,
primary3Color: Colors.lightBlack,
accent1Color: '#01A9F4',
accent2Color: Colors.grey100,
accent3Color: Colors.grey500,
textColor: Colors.darkBlack,
alternateTextColor: Colors.white,
canvasColor: Colors.white,
borderColor: Colors.grey300,
disabledColor: ColorManipulator.fade(Colors.darkBlack, 0.3)
}
};
Hope that helps :)

getting jquery working in rails

I have basic onclick functions* in my ruby on rails app, when i look at application.js, they're all available but in the frontend, when i actually click on the element, the function does not trigger, although when i try the HTML version equivalent, its working well.
The app has the jquery-rails Gem installed and just to double confirm, I also tried inserting the jquery.js file in the vendor folder, but neither of these solved it unfortunately
*example
$('#openSidebarButton').on('click', function() {
$('#openSidebarButton').addClass('hidden');
$('#sidebar').removeClass('hidden');
});
Please make sure you have the following in your application.js:
//= require jquery
//= require jquery_ujs
i found the solution..a bit silly of me but essentially, i did not include the function within document.ready, that's why it wasn't working :-)
to summarize, what i did was made the above mentioned on click within a function
$(document).ready(function() {
openSideBar();
});
function openSideBar {
$('#openSidebarButton').on('click', function() {
$('#openSidebarButton').addClass('hidden');
$('#sidebar').removeClass('hidden');
});
}

rails - asset pipeline - how to get newer version of jquery-ui included in the project?

I'm having a problem with the fullcalendar js which we use directly through the plugin (not the gem which is currently version incompatible anyway).
I'm upgrading rails from v3.2.6 to v3.2.8
fullcalendar is displaying the calendar ok but clicking to edit a date has a messed up ui (the action button are missgin their labels and there is no 'x' close link) and clicking to add a new event doesn't respond at all (as it's generating js errors).
I am getting these javascript errors:
Edit Event:
Uncaught TypeError: Object function ( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
return new jQuery.fn.init( selector, context, rootjQuery );
} has no method 'curCSS'
New event:
Uncaught SyntaxError: Unexpected token N
Our code:
LISA.dayClickHandler = function(day, allDay, jsEvent, view) {
$('#event_error_container').hide();
var hours = JSON.parse(day.getHours());
fullcalendar list the jquery-ui version for it as jquery-ui 1.8.23
However the jquery version in my application's vendor/assets/javascripts is 1.8.13 (I see this by literally opening up the file and looking at the comments at the top).
My own app/assets/javascripts library does not have any jquery.js or jquery_ui.js
My app/assets/javsacript directory has application.js which includes
...
// GO AFTER THE REQUIRES BELOW.
//
//= require jquery
//= require jquery_ujs
// more libraries
//= require jquery-ui
//= require jquery-autoSuggest.packed
...
Perhaps it might help to change my apps jquery-ui version from 1.8.13 to 1.8.23 to see if this resolves my issues but I am not sure of the right approach to do that.
This was a jquery-ui change ('curCSS' was removed) that was reversed (it was added back).
http://bugs.jquery.com/ticket/11921
The resolution was to download jquery-ui version 1.8.23 to vendor/assets/javascripts to replace the older version (1.8.11) and restart the server.

Resources