One simple way to do this without a script modifying the tiling per object is to apply the texture in worldspace. That way you'll always have a consistent repeat rate, no matter where or how stretched your objects are.
They'll also automatically tile seamlessly where two similarly-textured objects meet, even if they're using different scales (provided you've used a seamless tiling texture)
In this example you can see conventional texture mapping on the left, using four standard quads at different scales with one material. On the right are the same four quads textured in worldspace using a single material. (The brick texture is a free asset from Kenney.nl)
To do this, create a new shader something like the following:
Shader "Unlit/WorldspaceTiling"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
v2f vert (appdata v)
{
v2f o;
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
// Gets the xy position of the vertex in worldspace.
float2 worldXY = mul(_Object2World, v.vertex).xy;
// Use the worldspace coords instead of the mesh's UVs.
o.uv = TRANSFORM_TEX(worldXY, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
return col;
}
ENDCG
}
}
}
(Here I've used an unlit opaque shader without fog as a base, but other effects can be incorporated in a straightforward way if you need.) You can use the regular texture tiling & offset fields to fine-tune how many repeats you want per world unit and the alignment of the tiling.
This approach has some limitations:
If the object moves through worldspace (eg. a moving platform), the texture will appear to crawl along it.
Rotating the object won't rotate the texture, so it will tile across it diagonally.
An object that's not aligned to the texture's repetition grid can show the texture cropped incorrectly (eg. if you have a border that should always sit right at the edge of a tile)
These problems can all be worked around, the fixes just require a bit more information about your setup. If you have only a few objects that need special treatment, you can use the script approach described in the other answers for those, while the worldspace tiling handles the bulk of the simpler cases.
There are also some significant advantages:
No additional material instances created (which can leak if you're not careful - they're not garbage collected as readily as other objects)
Many differently-scaled objects can be rendered in one draw call since they use the same material (under the hood, Unity will often pre-transform vertices in order to send multiple scaled objects using the same material in one batch)
It "just works" without needing to add extra script instances