草庐IT

当我的主循环等待 channel 滴答和传递事件时,OpenGl 似乎卡住了

coder 2023-06-26 原文

我写了一个简单的 Go 程序。它的目标是使用 OpenGl 在屏幕上旋转一个三角形。

编辑:主循环似乎负责,OpenGl 很好,但我在 goroutines 和/或 channel 上做错了。请参阅本文底部。我正在适本地更改此问题的标题。

该程序几乎可以运行。它断断续续地在按预期旋转和只闪烁两个 OpenGl 缓冲区而不绘制任何东西之间交替。我尝试渲染的大约三分之二的帧无提示地失败了,我不明白为什么。

这不取决于我的帧率。无论我以 50 还是 1 FPS 更新,我都会得到一长串困惑的帧,然后是较短的工作帧系列。我不认为我要求 OpenGl 工作得太快(而且我还是调用了 glFinish())。

我开始试验并发现了一个奇怪的行为。 我使用 glGetUniformLocation 作为将我的新旋转矩阵发送到顶点缓冲区的第一步。 我注意到,如果我要求 glGetUniformLocation 告诉我在哪里可以找到 "dummy",一个显然在着色器中不存在的参数,它并不总是返回 -1正如预期的那样;它有时会返回 0。该虚拟属性与问题无关,它只是一种症状。

我在每次 OpenGl 调用后检查 glGetError,它们总是返回 NO_ERROR。

我在这里粘贴我的代码。我希望我能缩短它。我的真实代码在每次调用 OpenGl 后检查 glError,并查看 0 个缓冲区或 -1 个位置。这个版本更轻。 func main 位于顶部,后面是负责旋转的循环。

package main

import (
    "fmt"
    "github.com/0xe2-0x9a-0x9b/Go-SDL/sdl"
    gl "github.com/chsc/gogl/gl33"
    "math"
    "time"
    "unsafe"
)

const DEG_TO_RAD = math.Pi / 180

type GoMatrix [16]float64
type GlMatrix [16]gl.Float

var good_frames, bad_frames, sdl_events int

func main() {

    //=================================================================
    // Just opening a window, skip to the next part.

    if status := sdl.Init(sdl.INIT_VIDEO); status != 0 {
        panic("Could not initialize SDL: " + sdl.GetError())
    }
    defer sdl.Quit()

    sdl.GL_SetAttribute(sdl.GL_DOUBLEBUFFER, 1)
    const FLAGS = sdl.OPENGL
    if screen := sdl.SetVideoMode(640, 480, 32, FLAGS); screen == nil {
        panic("Could not open SDL window: " + sdl.GetError())
    }

    if err := gl.Init(); err != nil {
        panic(err)
    }

    gl.Viewport(0, 0, 640, 480)
    gl.ClearColor(.5, .5, .5, 1)

    //=================================================================
    // Simplest shaders ever.

    // A matrix to move the model, nothing else.
    vertex_code := gl.GLString(`
    #version 330 core
    in vec3 vpos;
    uniform mat4 MVP;
    void main() { 
        gl_Position = MVP * vec4(vpos, 1);
    }   
    `)
    // Everything is red.
    fragment_code := gl.GLString(`
    #version 330 core
    void main(){
        gl_FragColor = vec4(1,0,0,1);
    }
    `)
    vs := gl.CreateShader(gl.VERTEX_SHADER)
    fs := gl.CreateShader(gl.FRAGMENT_SHADER)
    gl.ShaderSource(vs, 1, &vertex_code, nil)
    gl.ShaderSource(fs, 1, &fragment_code, nil)
    gl.CompileShader(vs)
    gl.CompileShader(fs)
    prog := gl.CreateProgram()
    gl.AttachShader(prog, vs)
    gl.AttachShader(prog, fs)
    gl.LinkProgram(prog)
    // Did it compile?
    var link_status gl.Int
    gl.GetProgramiv(prog, gl.LINK_STATUS, &link_status)
    if link_status == gl.FALSE {
        var info_log_length gl.Int
        gl.GetProgramiv(prog, gl.INFO_LOG_LENGTH, &info_log_length)
        if info_log_length == 0 {
            panic("Program linking failed but OpenGL has no log about it.")
        } else {
            info_log_gl := gl.GLStringAlloc(gl.Sizei(info_log_length))
            defer gl.GLStringFree(info_log_gl)
            gl.GetProgramInfoLog(prog, gl.Sizei(info_log_length), nil, info_log_gl)
            info_log := gl.GoString(info_log_gl)
            panic(info_log)
        }
    }
    gl.UseProgram(prog)
    attrib_vpos := gl.Uint(gl.GetAttribLocation(prog, gl.GLString("vpos")))

    //=================================================================
    // One triangle.

    positions := [...]gl.Float{-.5, -.5, 0, .5, -.5, 0, 0, .5, 0}

    var vao gl.Uint
    gl.GenVertexArrays(1, &vao)
    gl.BindVertexArray(vao)

    var vbo gl.Uint
    gl.GenBuffers(1, &vbo)
    gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
    gl.BufferData(gl.ARRAY_BUFFER,
        gl.Sizeiptr(unsafe.Sizeof(positions)),
        gl.Pointer(&positions[0]),
        gl.STATIC_DRAW)

    gl.EnableVertexAttribArray(attrib_vpos)
    gl.VertexAttribPointer(attrib_vpos, 3, gl.FLOAT, gl.FALSE, 0, gl.Pointer(nil))

    //=================================================================

    Loop(prog)
    fmt.Println("Good frames", good_frames)
    fmt.Println("Bad frames ", bad_frames)
    fmt.Println("SDL events ", sdl_events)
}

func Loop(program gl.Uint) {
    start_time := time.Now()
    ticker := time.NewTicker(100 * time.Millisecond)
    defer ticker.Stop()
    running := true
    for running {
        select {
        case tick_time := <-ticker.C:
            OnTick(start_time, tick_time, program)
        case event := <-sdl.Events:
            running = OnSdlEvent(event)
        }
    }
}

func OnSdlEvent(event interface{}) bool {
    sdl_events++
    switch event.(type) {
    case sdl.QuitEvent:
        return false // Stop the main loop.
    }
    return true // Do not stop the main loop.
}

func OnTick(start_time, tick_time time.Time, program gl.Uint) {
    duration := tick_time.Sub(start_time).Seconds()
    speed := 10.
    angle := math.Mod(duration*speed, 360)
    gom := RotZ(angle)
    MVP := ToGlMatrix(gom)

    /* HERE, SOMETHING FISHY HAPPENS.

    Problem: sometimes, actually often, OpenGl returns 0 instead of -1 for
    the dummy parameter.  This is entirely correlated to the stuttering.

    With my implementation of OpenGl, swap buffer does a real swap.
    That means I get to see the last two pictures rendered.
    Thing is, I can see the swap, that means the pictures are different.
    That means that the call to DrawArrays is ignored.

    OpenGl is just crapping its pants.
    */
    matrix_loc := gl.GetUniformLocation(program, gl.GLString("MVP"))
    dummy_matrix_loc := gl.GetUniformLocation(program, gl.GLString("dummy"))
    if gl.GetError() != gl.NO_ERROR {
        fmt.Println("Error get location") // Never happens.
    }
    if dummy_matrix_loc == -1 {
        good_frames++ // Because is SHOULD fail.
    } else {
        bad_frames++ // That's not normal.
    }
    gl.UniformMatrix4fv(matrix_loc, 16, gl.TRUE, &MVP[0])
    if gl.GetError() != gl.NO_ERROR {
        fmt.Println("Error send matrix") // Never happens.
    }
    gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
    if gl.GetError() != gl.NO_ERROR {
        fmt.Println("Error clearing") // Never happens.
    }
    gl.DrawArrays(gl.TRIANGLES, 0, 3)
    if gl.GetError() != gl.NO_ERROR {
        fmt.Println("Error drawing") // Never happens.
    }
    gl.Finish() // Does not seem to make anything work better.
    sdl.GL_SwapBuffers()
}

func RotZ(angle float64) GoMatrix {
    var gom GoMatrix
    a := angle * DEG_TO_RAD
    c := math.Cos(a)
    s := math.Sin(a)
    gom[0] = c
    gom[1] = s
    gom[4] = -s
    gom[5] = c
    gom[10] = 1
    gom[15] = 1
    return gom
}

func ToGlMatrix(gom GoMatrix) GlMatrix {
    var glm GlMatrix
    glm[0] = gl.Float(gom[0])
    glm[1] = gl.Float(gom[1])
    glm[2] = gl.Float(gom[2])
    glm[3] = gl.Float(gom[3])
    glm[4] = gl.Float(gom[4])
    glm[5] = gl.Float(gom[5])
    glm[6] = gl.Float(gom[6])
    glm[7] = gl.Float(gom[7])
    glm[8] = gl.Float(gom[8])
    glm[9] = gl.Float(gom[9])
    glm[10] = gl.Float(gom[10])
    glm[11] = gl.Float(gom[11])
    glm[12] = gl.Float(gom[12])
    glm[13] = gl.Float(gom[13])
    glm[14] = gl.Float(gom[14])
    glm[15] = gl.Float(gom[15])
    return glm
}

根据要求,glxinfo 的输出。

> glxinfo
name of display: :0
display: :0  screen: 0
direct rendering: Yes
server glx vendor string: ATI
server glx version string: 1.4
server glx extensions:
    GLX_ARB_multisample, GLX_EXT_import_context, GLX_EXT_texture_from_pixmap, 
    GLX_EXT_visual_info, GLX_EXT_visual_rating, GLX_OML_swap_method, 
    GLX_SGI_make_current_read, GLX_SGI_swap_control, GLX_SGIS_multisample, 
    GLX_SGIX_fbconfig, GLX_SGIX_pbuffer, GLX_SGIX_visual_select_group
client glx vendor string: ATI
client glx version string: 1.4
client glx extensions:
    GLX_ARB_create_context, GLX_ARB_create_context_profile, 
    GLX_ARB_get_proc_address, GLX_ARB_multisample, GLX_EXT_import_context, 
    GLX_EXT_visual_info, GLX_EXT_visual_rating, GLX_MESA_allocate_memory, 
    GLX_MESA_copy_sub_buffer, GLX_MESA_swap_control, 
    GLX_MESA_swap_frame_usage, GLX_NV_swap_group, GLX_OML_swap_method, 
    GLX_SGI_make_current_read, GLX_SGI_swap_control, GLX_SGI_video_sync, 
    GLX_SGIS_multisample, GLX_SGIX_fbconfig, GLX_SGIX_pbuffer, 
    GLX_SGIX_swap_barrier, GLX_SGIX_swap_group, GLX_SGIX_visual_select_group, 
    GLX_EXT_texture_from_pixmap, GLX_EXT_framebuffer_sRGB, 
    GLX_ARB_fbconfig_float, GLX_AMD_gpu_association
GLX version: 1.4
GLX extensions:
    GLX_ARB_create_context, GLX_ARB_create_context_profile, 
    GLX_ARB_get_proc_address, GLX_ARB_multisample, GLX_EXT_import_context, 
    GLX_EXT_visual_info, GLX_EXT_visual_rating, GLX_MESA_swap_control, 
    GLX_NV_swap_group, GLX_OML_swap_method, GLX_SGI_make_current_read, 
    GLX_SGI_swap_control, GLX_SGI_video_sync, GLX_SGIS_multisample, 
    GLX_SGIX_fbconfig, GLX_SGIX_pbuffer, GLX_SGIX_swap_barrier, 
    GLX_SGIX_swap_group, GLX_SGIX_visual_select_group, 
    GLX_EXT_texture_from_pixmap
OpenGL vendor string: ATI Technologies Inc.
OpenGL renderer string: ATI Mobility Radeon HD 4500 Series
OpenGL version string: 3.3.11005 Compatibility Profile Context
OpenGL shading language version string: 3.30
OpenGL extensions:
    GL_AMDX_debug_output, GL_AMDX_vertex_shader_tessellator, 
    GL_AMD_conservative_depth, GL_AMD_debug_output, 
    GL_AMD_depth_clamp_separate, GL_AMD_draw_buffers_blend, 
    GL_AMD_name_gen_delete, GL_AMD_performance_monitor, GL_AMD_pinned_memory, 
    GL_AMD_sample_positions, GL_AMD_seamless_cubemap_per_texture, 
    GL_AMD_shader_stencil_export, GL_AMD_texture_cube_map_array, 
    GL_AMD_texture_texture4, GL_AMD_vertex_shader_tessellator, 
    GL_ARB_ES2_compatibility, GL_ARB_blend_func_extended, 
    GL_ARB_color_buffer_float, GL_ARB_copy_buffer, GL_ARB_depth_buffer_float, 
    GL_ARB_depth_clamp, GL_ARB_depth_texture, GL_ARB_draw_buffers, 
    GL_ARB_draw_buffers_blend, GL_ARB_draw_elements_base_vertex, 
    GL_ARB_draw_instanced, GL_ARB_explicit_attrib_location, 
    GL_ARB_fragment_coord_conventions, GL_ARB_fragment_program, 
    GL_ARB_fragment_program_shadow, GL_ARB_fragment_shader, 
    GL_ARB_framebuffer_object, GL_ARB_framebuffer_sRGB, 
    GL_ARB_geometry_shader4, GL_ARB_get_program_binary, 
    GL_ARB_half_float_pixel, GL_ARB_half_float_vertex, GL_ARB_imaging, 
    GL_ARB_instanced_arrays, GL_ARB_map_buffer_range, GL_ARB_multisample, 
    GL_ARB_multitexture, GL_ARB_occlusion_query, GL_ARB_occlusion_query2, 
    GL_ARB_pixel_buffer_object, GL_ARB_point_parameters, GL_ARB_point_sprite, 
    GL_ARB_provoking_vertex, GL_ARB_sample_shading, GL_ARB_sampler_objects, 
    GL_ARB_seamless_cube_map, GL_ARB_separate_shader_objects, 
    GL_ARB_shader_bit_encoding, GL_ARB_shader_objects, 
    GL_ARB_shader_precision, GL_ARB_shader_stencil_export, 
    GL_ARB_shader_texture_lod, GL_ARB_shading_language_100, GL_ARB_shadow, 
    GL_ARB_shadow_ambient, GL_ARB_sync, GL_ARB_texture_border_clamp, 
    GL_ARB_texture_buffer_object, GL_ARB_texture_buffer_object_rgb32, 
    GL_ARB_texture_compression, GL_ARB_texture_compression_rgtc, 
    GL_ARB_texture_cube_map, GL_ARB_texture_cube_map_array, 
    GL_ARB_texture_env_add, GL_ARB_texture_env_combine, 
    GL_ARB_texture_env_crossbar, GL_ARB_texture_env_dot3, 
    GL_ARB_texture_float, GL_ARB_texture_gather, 
    GL_ARB_texture_mirrored_repeat, GL_ARB_texture_multisample, 
    GL_ARB_texture_non_power_of_two, GL_ARB_texture_query_lod, 
    GL_ARB_texture_rectangle, GL_ARB_texture_rg, GL_ARB_texture_rgb10_a2ui, 
    GL_ARB_texture_snorm, GL_ARB_timer_query, GL_ARB_transform_feedback2, 
    GL_ARB_transform_feedback3, GL_ARB_transpose_matrix, 
    GL_ARB_uniform_buffer_object, GL_ARB_vertex_array_bgra, 
    GL_ARB_vertex_array_object, GL_ARB_vertex_buffer_object, 
    GL_ARB_vertex_program, GL_ARB_vertex_shader, 
    GL_ARB_vertex_type_2_10_10_10_rev, GL_ARB_viewport_array, 
    GL_ARB_window_pos, GL_ATI_draw_buffers, GL_ATI_envmap_bumpmap, 
    GL_ATI_fragment_shader, GL_ATI_meminfo, GL_ATI_separate_stencil, 
    GL_ATI_texture_compression_3dc, GL_ATI_texture_env_combine3, 
    GL_ATI_texture_float, GL_ATI_texture_mirror_once, GL_EXT_abgr, 
    GL_EXT_bgra, GL_EXT_bindable_uniform, GL_EXT_blend_color, 
    GL_EXT_blend_equation_separate, GL_EXT_blend_func_separate, 
    GL_EXT_blend_minmax, GL_EXT_blend_subtract, GL_EXT_compiled_vertex_array, 
    GL_EXT_copy_buffer, GL_EXT_copy_texture, GL_EXT_direct_state_access, 
    GL_EXT_draw_buffers2, GL_EXT_draw_instanced, GL_EXT_draw_range_elements, 
    GL_EXT_fog_coord, GL_EXT_framebuffer_blit, GL_EXT_framebuffer_multisample, 
    GL_EXT_framebuffer_object, GL_EXT_framebuffer_sRGB, 
    GL_EXT_geometry_shader4, GL_EXT_gpu_program_parameters, 
    GL_EXT_gpu_shader4, GL_EXT_histogram, GL_EXT_multi_draw_arrays, 
    GL_EXT_packed_depth_stencil, GL_EXT_packed_float, GL_EXT_packed_pixels, 
    GL_EXT_pixel_buffer_object, GL_EXT_point_parameters, 
    GL_EXT_provoking_vertex, GL_EXT_rescale_normal, GL_EXT_secondary_color, 
    GL_EXT_separate_specular_color, GL_EXT_shadow_funcs, GL_EXT_stencil_wrap, 
    GL_EXT_subtexture, GL_EXT_texgen_reflection, GL_EXT_texture3D, 
    GL_EXT_texture_array, GL_EXT_texture_buffer_object, 
    GL_EXT_texture_compression_latc, GL_EXT_texture_compression_rgtc, 
    GL_EXT_texture_compression_s3tc, GL_EXT_texture_cube_map, 
    GL_EXT_texture_edge_clamp, GL_EXT_texture_env_add, 
    GL_EXT_texture_env_combine, GL_EXT_texture_env_dot3, 
    GL_EXT_texture_filter_anisotropic, GL_EXT_texture_integer, 
    GL_EXT_texture_lod, GL_EXT_texture_lod_bias, GL_EXT_texture_mirror_clamp, 
    GL_EXT_texture_object, GL_EXT_texture_rectangle, GL_EXT_texture_sRGB, 
    GL_EXT_texture_shared_exponent, GL_EXT_texture_snorm, 
    GL_EXT_texture_swizzle, GL_EXT_timer_query, GL_EXT_transform_feedback, 
    GL_EXT_vertex_array, GL_EXT_vertex_array_bgra, 
    GL_IBM_texture_mirrored_repeat, GL_KTX_buffer_region, GL_NV_blend_square, 
    GL_NV_conditional_render, GL_NV_copy_depth_to_color, 
    GL_NV_explicit_multisample, GL_NV_float_buffer, GL_NV_half_float, 
    GL_NV_primitive_restart, GL_NV_texgen_reflection, GL_NV_texture_barrier, 
    GL_SGIS_generate_mipmap, GL_SGIS_texture_edge_clamp, GL_SGIS_texture_lod, 
    GL_SUN_multi_draw_arrays, GL_WIN_swap_hint, WGL_EXT_swap_control

编辑:主循环似乎是负责任的,OpenGl 很好,但我在 goroutines 和/或 channel 上做错了。

如果我用不依赖 channel 和 goroutines 的东西替换我的主循环,那么 OpenGl 表现完美。

func Loop(program gl.Uint) {
    start_time := time.Now()
    stop_time := start_time.Add(time.Duration(30 * time.Second))
    running := true
    for running {
        tick_time := time.Now()
        OnTick(start_time, tick_time, program)
        time.Sleep(10 * time.Millisecond)
        if tick_time.After(stop_time) {
            running = false
        }
    }
}

我的问题可能是因为 OpenGl 在主 Goroutine 中,它在等待 channel 传递 tick 或 SDL 事件时阻塞。我不知道,我很困惑。

将标题从 glGetUniformLocation 对于不存在的属性通常返回 0 而不是 -1 更改为 OpenGl 似乎卡住了,而我的主循环等待 channel 滴答和传递事件。

最佳答案

问题出在图形库 SDL 和 OpenGl 对线程的使用施加了限制。 Golang 在它认为合适的情况下在线程之间移动 goroutines,不知道这些限制。因此,一些调用会丢失,出现不可预知的行为。

通过将 OpenGl 锁定到主线程,我可以让它工作,而不必放弃使用 goroutines。

这是我采用的解决方案: http://code.google.com/p/go-wiki/wiki/LockOSThread 请注意函数 do 中有一个拼写错误:应该读作 mainfunc 而不是 ch

我的主文件现在看起来像这样:

// Arrange that main.main runs on main thread.
func init() {
    runtime.LockOSThread()
}

// Queue of work to run in main thread.
var mainfunc = make(chan func())

// Run all the functions that need to run in the main thread.
func Main() {
    for f = range mainfunc {
        f()
    }
}

// Put the function f on the main thread function queue.
func do(f func()) {
    done := make(chan bool, 1)
    mainfunc <- func() {
        f()
        done <- true
    }
    <-done

// The real main function.
func main() {
    go Everything()
    Main()
}

// Your entire application comes here.
func Everything() {
    defer close(mainfunc)
    do(func(){
        // init SDL, OpenGl, all that.
    })
    defer sdl.Quit()

    var some_variable int // Starts at 0.
    do(func(){
        // OpenGl code
        some_variable = 42 // Closure allows for communication.
    })
    Loop(some_variable) // Now 42.
}

关于当我的主循环等待 channel 滴答和传递事件时,OpenGl 似乎卡住了,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14732354/

有关当我的主循环等待 channel 滴答和传递事件时,OpenGl 似乎卡住了的更多相关文章

  1. ruby-on-rails - 如何在我的 Rails 应用程序 View 中打印 ruby​​ 变量的内容? - 2

    我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby​​中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R

  2. ruby - 我可以将我的 README.textile 以正确的格式放入我的 RDoc 中吗? - 2

    我喜欢使用Textile或Markdown为我的项目编写自述文件,但是当我生成RDoc时,自述文件被解释为RDoc并且看起来非常糟糕。有没有办法让RDoc通过RedCloth或BlueCloth而不是它自己的格式化程序运行文件?它可以配置为自动检测文件后缀的格式吗?(例如README.textile通过RedCloth运行,但README.mdown通过BlueCloth运行) 最佳答案 使用YARD直接代替RDoc将允许您包含Textile或Markdown文件,只要它们的文件后缀是合理的。我经常使用类似于以下Rake任务的东西:

  3. jquery - 我的 jquery AJAX POST 请求无需发送 Authenticity Token (Rails) - 2

    rails中是否有任何规定允许站点的所有AJAXPOST请求在没有authenticity_token的情况下通过?我有一个调用Controller方法的JqueryPOSTajax调用,但我没有在其中放置任何真实性代码,但调用成功。我的ApplicationController确实有'request_forgery_protection'并且我已经改变了config.action_controller.consider_all_requests_local在我的environments/development.rb中为false我还搜索了我的代码以确保我没有重载ajaxSend来发送

  4. ruby - rails 3 redirect_to 将参数传递给命名路由 - 2

    我没有找到太多关于如何执行此操作的信息,尽管有很多关于如何使用像这样的redirect_to将参数传递给重定向的建议:action=>'something',:controller=>'something'在我的应用程序中,我在路由文件中有以下内容match'profile'=>'User#show'我的表演Action是这样的defshow@user=User.find(params[:user])@title=@user.first_nameend重定向发生在同一个用户Controller中,就像这样defregister@title="Registration"@user=Use

  5. ruby-on-rails - 如何生成传递一些自定义参数的 `link_to` URL? - 2

    我正在使用RubyonRails3.0.9,我想生成一个传递一些自定义参数的link_toURL。也就是说,有一个articles_path(www.my_web_site_name.com/articles)我想生成如下内容:link_to'Samplelinktitle',...#HereIshouldimplementthecode#=>'http://www.my_web_site_name.com/articles?param1=value1¶m2=value2&...我如何编写link_to语句“alàRubyonRailsWay”以实现该目的?如果我想通过传递一些

  6. java - 我的模型类或其他类中应该有逻辑吗 - 2

    我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

  7. ruby-on-rails - 事件管理员日期过滤器日期格式自定义 - 2

    是否有简单的方法来更改默认ISO格式(yyyy-mm-dd)的ActiveAdmin日期过滤器显示格式? 最佳答案 您可以像这样为日期选择器提供额外的选项,而不是覆盖js:=f.input:my_date,as::datepicker,datepicker_options:{dateFormat:"mm/dd/yy"} 关于ruby-on-rails-事件管理员日期过滤器日期格式自定义,我们在StackOverflow上找到一个类似的问题: https://s

  8. ruby - 在 Ruby 中按名称传递函数 - 2

    如何在Ruby中按名称传递函数?(我使用Ruby才几个小时,所以我还在想办法。)nums=[1,2,3,4]#Thisworks,butismoreverbosethanI'dlikenums.eachdo|i|putsiend#InJS,Icouldjustdosomethinglike:#nums.forEach(console.log)#InF#,itwouldbesomethinglike:#List.iternums(printf"%A")#InRuby,IwishIcoulddosomethinglike:nums.eachputs在Ruby中能不能做到类似的简洁?我可以只

  9. ruby-on-rails - 在 heroku 的 .fonts 文件夹中包含自定义字体,似乎无法识别它们 - 2

    Heroku支持人员告诉我,为了在我的Web应用程序中使用自定义字体(未安装在系统中,您可以在bash控制台中使用fc-list查看已安装的字体)我必须部署一个包含所有字体的.fonts文件夹里面的字体。问题是我不知道该怎么做。我的意思是,我不知道文件名是否必须遵循heroku的任何特殊模式,或者我必须在我的代码中做一些事情来考虑这种字体,或者如果我将它包含在文件夹中它是自动的......事实是,我尝试以不同的方式更改字体的文件名,但根本没有使用该字体。为了提供更多详细信息,我们使用字体的过程是将PDF转换为图像,更具体地说,使用rghostgem。并且最终图像根本不使用自定义字体。在

  10. ruby-on-rails - 事件记录 : Select max of limit - 2

    我正在尝试将以下SQL查询转换为ActiveRecord,它正在融化我的大脑。deletefromtablewhereid有什么想法吗?我想做的是限制表中的行数。所以,我想删除少于最近10个条目的所有内容。编辑:通过结合以下几个答案找到了解决方案。Temperature.where('id这给我留下了最新的10个条目。 最佳答案 从您的SQL来看,您似乎想要从表中删除前10条记录。我相信到目前为止的大多数答案都会如此。这里有两个额外的选择:基于MurifoX的版本:Table.where(:id=>Table.order(:id).

随机推荐