Help with placing a character on a part

The title pretty much summarizes it, I’m making a simple rail grinding script but I cannot figure out how to place the player directly on top of the rail from any angle.

The bug is where I create the Position variable (Line 28), if the rail is not parallel to the z-axis then it just won’t position the player on top of the rail correctly. I don’t want the player to be at the middle of the rail, but, I’m not sure how to explain it, just on top of the rail from where the player is

How do I make it so that the player will be positioned correctly no matter the angle? Fixing the script or script examples would be very much appreciated.

local RunService = game:GetService("RunService")

local Player = game.Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local HumanoidRootPart = Character:WaitForChild("HumanoidRootPart")

local RailGrinding = false -- True if the player is grinding on a rail, if true the script will not run again until false.
local RailSpeed = 5 -- How fast the player moves along the rail

for _, BodyPart in pairs(Character:GetChildren()) do
	if BodyPart:IsA("BasePart") or BodyPart:IsA("MeshPart") then -- Single out the children of the Character that are Body Parts (e.g legs)

		BodyPart.Touched:Connect(function(Rail)
			if not RailGrinding then
				if Rail.Parent:FindFirstChild("_Rail") then -- Check if the touched part is a rail			
					RailGrinding = true -- If false, the thread will run again

					--[[ CREATING VARIABLES ]]--
					local BodyPosition = Instance.new("BodyPosition")
					BodyPosition.P = 100000
					BodyPosition.D = 5

					local Sign = math.sign(HumanoidRootPart.CFrame.LookVector.X)
					if Sign == 0 then
						Sign = 1
					end
					local Direction = Rail.CFrame.LookVector:Abs() -- Get the direction the rail is facing, this is to move the player along the rail
				
					local Position = CFrame.new(Vector3.new(HumanoidRootPart.Position.X, Rail.Position.Y + 5, Rail.Position.Z))

					Character:PivotTo(Position)

					local Looping = true -- If false, the loop will end
					local Boosting = false -- If true, the speed will increase

					--[[ MOVING THE PLAYER ]]--
					while RunService.Heartbeat:Wait() do
						local Movement = (RailSpeed/10)*Sign*Direction
						Position += Movement
						BodyPosition.Position =  Position.Position
						Character:PivotTo(Position)

						local Params = RaycastParams.new() -- For Raycasting (Below)	
						Params.FilterDescendantsInstances = {Character} -- Ignores children of your character
						Params.FilterType = Enum.RaycastFilterType.Exclude

						--[[ KICK OFF THE PLAYER IF... ]]--
						local RayCast = workspace:Raycast(HumanoidRootPart.Position, Vector3.new(0, -10, 0), Params) -- Cast the ray with params
						if RayCast and RayCast.Instance then
							if RayCast.Instance.Parent:FindFirstChild("_Rail") then
								-- The ray hit a rail, update the Rail variable
								Rail = RayCast.Instance
								Direction = Rail.CFrame.LookVector:Abs()
							else
								-- The ray hit something other than a rail, kick off the player
								Looping = false
							end
						else
							-- The ray didnt hit anything, kick off the player
							Looping = false
						end

						game:GetService("UserInputService").InputBegan:Connect(function(input,gpe)
							if not gpe and input.KeyCode == Enum.KeyCode.Space then -- Jump off from the rail
								Looping = false
							end
						end)

						if Looping == false then -- What did this do again?
							BodyPosition:Destroy()
							wait(0.25)
							RailGrinding = false
							break
						end
					end
				end
			end
		end)
	end
end